<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>OAuth 2.0 Resource Server :: Spring Security</title>
<link rel="canonical" href="oauth2-resourceserver.html">
<link rel="prev" href="oauth2-client.html">
<link rel="next" href="../saml2/index.html">
<meta name="generator" content="Antora 3.0.0">
<link rel="stylesheet" href="../../../_/css/site.css">
<link href="../../../_/img/favicon.ico" rel='shortcut icon' type='image/vnd.microsoft.icon'>
<link rel="stylesheet" href="../../../_/css/vendor/docsearch.min.css">

<script>var uiRootPath = '../../../_'</script>
</head>
<body class="article">
<header class="header">
<nav class="navbar">
<div class="navbar-brand">
<a class="navbar-item" href="https://spring.io">
<img id="springlogo" class="block" src="../../../_/img/spring-logo.svg" alt="Spring">
</a>
<button class="navbar-burger" data-target="topbar-nav">
<span></span>
<span></span>
<span></span>
</button>
</div>
<div id="topbar-nav" class="navbar-menu">
<div class="navbar-end">
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link" href="oauth2-resourceserver.html#">Why Spring</a>
<div class="navbar-dropdown">
<a class="navbar-item" href="https://spring.io/why-spring">Overview</a>
<a class="navbar-item" href="https://spring.io/microservices">Microservices</a>
<a class="navbar-item" href="https://spring.io/reactive">Reactive</a>
<a class="navbar-item" href="https://spring.io/event-driven">Event Driven</a>
<a class="navbar-item" href="https://spring.io/cloud">Cloud</a>
<a class="navbar-item" href="https://spring.io/web-applications">Web Applications</a>
<a class="navbar-item" href="https://spring.io/serverless">Serverless</a>
<a class="navbar-item" href="https://spring.io/batch">Batch</a>
</div>
</div>
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link" href="oauth2-resourceserver.html#">Learn</a>
<div class="navbar-dropdown">
<a class="navbar-item" href="https://spring.io/learn">Overview</a>
<a class="navbar-item" href="https://spring.io/quickstart">Quickstart</a>
<a class="navbar-item" href="https://spring.io/guides">Guides</a>
<a class="navbar-item" href="https://spring.io/blog">Blog</a>
</div>
</div>
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link" href="oauth2-resourceserver.html#">Projects</a>
<div class="navbar-dropdown">
<a class="navbar-item" href="https://spring.io/projects">Overview</a>
<a class="navbar-item" href="https://spring.io/projects/spring-boot">Spring Boot</a>
<a class="navbar-item" href="https://spring.io/projects/spring-framework">Spring Framework</a>
<a class="navbar-item" href="https://spring.io/projects/spring-cloud">Spring Cloud</a>
<a class="navbar-item" href="https://spring.io/projects/spring-cloud-dataflow">Spring Cloud Data Flow</a>
<a class="navbar-item" href="https://spring.io/projects/spring-data">Spring Data</a>
<a class="navbar-item" href="https://spring.io/projects/spring-integration">Spring Integration</a>
<a class="navbar-item" href="https://spring.io/projects/spring-batch">Spring Batch</a>
<a class="navbar-item" href="https://spring.io/projects/spring-security">Spring Security</a>
<a class="navbar-item navbar-item-special" href="https://spring.io/projects">View all projects</a>
<a class="navbar-item" href="https://spring.io/tools">Spring Tools 4</a>
<a class="navbar-item navbar-item-special-2" href="https://start.spring.io">Spring Initializr <svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><polyline points="15 10.94 15 15 1 15 1 1 5.06 1" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="2"></polyline><polyline points="8.93 1 15 1 15 7.07" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="2"></polyline><line x1="15" y1="1" x2="8" y2="8" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="2"></line></svg></a>
</div>
</div>
<a class="navbar-item" href="https://spring.io/training">Training</a>
<a class="navbar-item" href="https://spring.io/support">Support</a>
<div class="navbar-item has-dropdown is-hoverable is-community">
<a class="navbar-link" href="oauth2-resourceserver.html#">Community</a>
<div class="navbar-dropdown">
<a class="navbar-item" href="https://spring.io/community">Overview</a>
<a class="navbar-item" href="https://spring.io/events">Events</a>
<a class="navbar-item" href="https://spring.io/team">Team</a>
</div>
</div>
</div>
</div>
<div id="switch-theme">
<input type="checkbox" id="switch-theme-checkbox" />
<label for="switch-theme-checkbox">Dark Theme</label>
</div>
</nav>
</header>
<div class="body">
<div class="nav-container" data-component="ROOT" data-version="5.6.0-RC1">
<aside class="nav">
<div class="panels">
<div class="nav-panel-menu is-active" data-panel="menu">
<nav class="nav-menu">
<h3 class="title"><a href="../../index.html">Spring Security</a></h3>
<ul class="nav-list">
<li class="nav-item" data-depth="0">
<ul class="nav-list">
<li class="nav-item" data-depth="1">
<a class="nav-link" href="../../index.html">Overview</a>
</li>
<li class="nav-item" data-depth="1">
<a class="nav-link" href="../../prerequisites.html">Prerequisites</a>
</li>
<li class="nav-item" data-depth="1">
<a class="nav-link" href="../../community.html">Community</a>
</li>
<li class="nav-item" data-depth="1">
<a class="nav-link" href="../../whats-new.html">What&#8217;s New</a>
</li>
<li class="nav-item" data-depth="1">
<a class="nav-link" href="../../getting-spring-security.html">Getting Spring Security</a>
</li>
<li class="nav-item" data-depth="1">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="../../features/index.html">Features</a>
<ul class="nav-list">
<li class="nav-item" data-depth="2">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="../../features/authentication/index.html">Authentication</a>
<ul class="nav-list">
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../features/authentication/password-storage.html">Password Storage</a>
</li>
</ul>
</li>
<li class="nav-item" data-depth="2">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="../../features/exploits/index.html">Protection Against Exploits</a>
<ul class="nav-list">
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../features/exploits/csrf.html">CSRF</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../features/exploits/headers.html">HTTP Headers</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../features/exploits/http.html">HTTP Requests</a>
</li>
</ul>
</li>
<li class="nav-item" data-depth="2">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="../../features/integrations/index.html">Integrations</a>
<ul class="nav-list">
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../features/integrations/cryptography.html">Cryptography</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../features/integrations/data.html">Spring Data</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../features/integrations/concurrency.html">Java&#8217;s Concurrency APIs</a>
</li>
<li class="nav-item" data-depth="3">
 <a class="nav-link" href="../../features/integrations/jackson.html">Jackson</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../features/integrations/localization.html">Localization</a>
</li>
</ul>
</li>
</ul>
</li>
<li class="nav-item" data-depth="1">
<a class="nav-link" href="../../modules.html">Project Modules</a>
</li>
<li class="nav-item" data-depth="1">
<a class="nav-link" href="../../samples.html">Samples</a>
</li>
<li class="nav-item" data-depth="1">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="../index.html">Servlet Applications</a>
<ul class="nav-list">
<li class="nav-item" data-depth="2">
<a class="nav-link" href="../getting-started.html">Getting Started</a>
</li>
<li class="nav-item" data-depth="2">
<a class="nav-link" href="../architecture.html">Architecture</a>
</li>
<li class="nav-item" data-depth="2">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="../authentication/index.html">Authentication</a>
<ul class="nav-list">
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../authentication/architecture.html">Authentication Architecture</a>
</li>
<li class="nav-item" data-depth="3">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="../authentication/passwords/index.html">Username/Password</a>
<ul class="nav-list">
<li class="nav-item" data-depth="4">
<button class="nav-item-toggle"></button>
<span class="nav-text">Reading Username/Password</span>
<ul class="nav-list">
<li class="nav-item" data-depth="5">
<a class="nav-link" href="../authentication/passwords/form.html">Form</a>
</li>
<li class="nav-item" data-depth="5">
<a class="nav-link" href="../authentication/passwords/basic.html">Basic</a>
</li>
<li class="nav-item" data-depth="5">
<a class="nav-link" href="../authentication/passwords/digest.html">Digest</a>
</li>
</ul>
</li>
<li class="nav-item" data-depth="4">
<button class="nav-item-toggle"></button>
<span class="nav-text">Password Storage</span>
<ul class="nav-list">
<li class="nav-item" data-depth="5">
<a class="nav-link" href="../authentication/passwords/in-memory.html">In Memory</a>
</li>
<li class="nav-item" data-depth="5">
<a class="nav-link" href="../authentication/passwords/jdbc.html">JDBC</a>
</li>
<li class="nav-item" data-depth="5">
<a class="nav-link" href="../authentication/passwords/user-details.html">UserDetails</a>
</li>
<li class="nav-item" data-depth="5">
<a class="nav-link" href="../authentication/passwords/user-details-service.html">UserDetailsService</a>
</li>
<li class="nav-item" data-depth="5">
<a class="nav-link" href="../authentication/passwords/password-encoder.html">PasswordEncoder</a>
</li>
<li class="nav-item" data-depth="5">
<a class="nav-link" href="../authentication/passwords/dao-authentication-provider.html">DaoAuthenticationProvider</a>
</li>
<li class="nav-item" data-depth="5">
<a class="nav-link" href="../authentication/passwords/ldap.html">LDAP</a>
</li>
</ul>
</li>
</ul>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../authentication/session-management.html">Session Management</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../authentication/rememberme.html">Remember Me</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../authentication/openid.html">OpenID</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../authentication/anonymous.html">Anonymous</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../authentication/preauth.html">Pre-Authentication</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../authentication/jaas.html">JAAS</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../authentication/cas.html">CAS</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../authentication/x509.html">X509</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../authentication/runas.html">Run-As</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../authentication/logout.html">Logout</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../authentication/events.html">Authentication Events</a>
</li>
</ul>
</li>
<li class="nav-item" data-depth="2">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="../authorization/index.html">Authorization</a>
<ul class="nav-list">
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../authorization/architecture.html">Authorization Architecture</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../authorization/authorize-requests.html">Authorize HTTP Requests</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../authorization/expression-based.html">Expression-Based Access Control</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../authorization/secure-objects.html">Secure Object Implementations</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../authorization/method-security.html">Method Security</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../authorization/acls.html">Domain Object Security ACLs</a>
</li>
</ul>
</li>
<li class="nav-item" data-depth="2">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="index.html">OAuth2</a>
<ul class="nav-list">
<li class="nav-item" data-depth="3">
<a class="nav-link" href="oauth2-login.html">OAuth2 Log In</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="oauth2-client.html">OAuth2 Client</a>
</li>
<li class="nav-item is-current-page" data-depth="3">
<a class="nav-link" href="oauth2-resourceserver.html">OAuth2 Resource Server</a>
</li>
</ul>
</li>
<li class="nav-item" data-depth="2">
<a class="nav-link" href="../saml2/index.html">SAML2</a>
</li>
<li class="nav-item" data-depth="2">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="../exploits/index.html">Protection Against Exploits</a>
<ul class="nav-list">
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../exploits/csrf.html">Cross Site Request Forgery (CSRF) for Servlet Environments</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../exploits/headers.html">Security HTTP Response Headers</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../exploits/http.html">HTTP</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../exploits/firewall.html">HttpFirewall</a>
</li>
</ul>
</li>
<li class="nav-item" data-depth="2">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="../integrations/index.html">Integrations</a>
<ul class="nav-list">
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../integrations/servlet-api.html">Servlet APIs</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../integrations/mvc.html">Spring MVC</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../integrations/websocket.html">WebSocket</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../integrations/cors.html">Spring&#8217;s CORS Support</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../integrations/jsp-taglibs.html">JSP Taglib</a>
</li>
</ul>
</li>
<li class="nav-item" data-depth="2">
<button class="nav-item-toggle"></button>
<span class="nav-text">Configuration</span>
<ul class="nav-list">
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../configuration/java.html">Java Configuration</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../configuration/kotlin.html">Kotlin Configuration</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../configuration/xml-namespace.html">Namespace Configuration</a>
</li>
</ul>
</li>
<li class="nav-item" data-depth="2">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="../test/index.html">Testing</a>
<ul class="nav-list">
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../test/method.html">Method Security</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../test/mockmvc.html">MockMvc Support</a>
</li>
</ul>
</li>
<li class="nav-item" data-depth="2">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="../appendix/index.html">Appendix</a>
<ul class="nav-list">
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../appendix/database-schema.html">Database Schemas</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../appendix/namespace.html">XML Namespace</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../appendix/faq.html">FAQ</a>
</li>
</ul>
</li>
</ul>
</li>
<li class="nav-item" data-depth="1">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="../../reactive/index.html">Reactive Applications</a>
<ul class="nav-list">
<li class="nav-item" data-depth="2">
<a class="nav-link" href="../../reactive/getting-started.html">Getting Started</a>
</li>
<li class="nav-item" data-depth="2">
<button class="nav-item-toggle"></button>
<span class="nav-text">Authentication</span>
<ul class="nav-list">
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../reactive/authentication/x509.html">X.509 Authentication</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../reactive/authentication/logout.html">Logout</a>
</li>
</ul>
</li>
<li class="nav-item" data-depth="2">
<button class="nav-item-toggle"></button>
<span class="nav-text">Authorization</span>
<ul class="nav-list">
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../reactive/authorization/method.html">EnableReactiveMethodSecurity</a>
</li>
</ul>
</li>
<li class="nav-item" data-depth="2">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="../../reactive/oauth2/index.html">OAuth2</a>
<ul class="nav-list">
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../reactive/oauth2/login.html">OAuth 2.0 Login</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../reactive/oauth2/oauth2-client.html">OAuth2 Client</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../reactive/oauth2/resource-server.html">OAuth 2.0 Resource Server</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../reactive/registered-oauth2-authorized-client.html">@RegisteredOAuth2AuthorizedClient</a>
</li>
</ul>
</li>
<li class="nav-item" data-depth="2">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="../../reactive/exploits/index.html">Protection Against Exploits</a>
<ul class="nav-list">
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../reactive/exploits/csrf.html">CSRF</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../reactive/exploits/headers.html">Headers</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../reactive/exploits/http.html">HTTP Requests</a>
</li>
</ul>
</li>
<li class="nav-item" data-depth="2">
<button class="nav-item-toggle"></button>
<span class="nav-text">Integrations</span>
<ul class="nav-list">
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../reactive/integrations/cors.html">CORS</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../reactive/integrations/rsocket.html">RSocket</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../reactive/integrations/webclient.html">WebClient</a>
</li>
</ul>
</li>
<li class="nav-item" data-depth="2">
<a class="nav-link" href="../../reactive/test.html">Testing</a>
</li>
<li class="nav-item" data-depth="2">
<a class="nav-link" href="../../reactive/configuration/webflux.html">WebFlux Security</a>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</nav>
</div>
<div class="nav-panel-explore" data-panel="explore">
<div class="context">
<span class="title">Spring Security</span>
<span class="version">5.6.0-RC1</span>
</div>
<ul class="components">
<li class="component is-current">
<a class="title" href="../../../index.html">Spring Security</a>
<ul class="versions">
<li class="version">
<a href="../../../6.0/index.html">6.0.0-SNAPSHOT</a>
</li>
<li class="version">
<a href="../../../6.0.0-M3/index.html">6.0.0-M3</a>
</li>
<li class="version">
<a href="../../../6.0.0-M2/index.html">6.0.0-M2</a>
</li>
<li class="version">
<a href="../../../6.0.0-M1/index.html">6.0.0-M1</a>
</li>
<li class="version">
<a href="../../../5.7/index.html">5.7.0-SNAPSHOT</a>
</li>
<li class="version">
<a href="../../../5.7.0-RC1/index.html">5.7.0-RC1</a>
</li>
<li class="version">
<a href="../../../5.7.0-M3/index.html">5.7.0-M3</a>
</li>
<li class="version">
<a href="../../../5.7.0-M2/index.html">5.7.0-M2</a>
</li>
<li class="version">
<a href="../../../5.7.0-M1/index.html">5.7.0-M1</a>
</li>
<li class="version">
<a href="../../../5.6.4/index.html">5.6.4-SNAPSHOT</a>
</li>
<li class="version is-latest">
<a href="../../../index.html">5.6.3</a>
</li>
<li class="version">
<a href="../../../5.6.2/index.html">5.6.2</a>
</li>
<li class="version">
<a href="../../../5.6.1/index.html">5.6.1</a>
</li>
<li class="version">
<a href="../../../5.6.0/index.html">5.6.0</a>
</li>
<li class="version is-current">
<a href="../../index.html">5.6.0-RC1</a>
</li>
</ul>
</li>
</ul>
</div>
</div>
</aside>
</div>
<main class="article">
<div class="toolbar" role="navigation">
<button class="nav-toggle"></button>
<nav class="breadcrumbs" aria-label="breadcrumbs">
<ul>
<li><a href="../../index.html">Spring Security</a></li>
<li><a href="../index.html">Servlet Applications</a></li>
<li><a href="index.html">OAuth2</a></li>
<li><a href="oauth2-resourceserver.html">OAuth2 Resource Server</a></li>
</ul>
</nav>
<div class="search">
<input id="search-input" type="text" placeholder="Search docs">
</div>
<div class="page-versions">
<button class="version-menu-toggle" title="Show other versions of page">5.6.0-RC1</button>
<div class="version-menu">
<a class="version is-missing" href="../../../6.0/index.html">6.0.0-SNAPSHOT</a>
<a class="version is-missing" href="../../../6.0.0-M3/index.html">6.0.0-M3</a>
<a class="version is-missing" href="../../../6.0.0-M2/index.html">6.0.0-M2</a>
<a class="version is-missing" href="../../../6.0.0-M1/index.html">6.0.0-M1</a>
<a class="version is-missing" href="../../../5.7/index.html">5.7.0-SNAPSHOT</a>
<a class="version is-missing" href="../../../5.7.0-RC1/index.html">5.7.0-RC1</a>
<a class="version is-missing" href="../../../5.7.0-M3/index.html">5.7.0-M3</a>
<a class="version is-missing" href="../../../5.7.0-M2/index.html">5.7.0-M2</a>
<a class="version is-missing" href="../../../5.7.0-M1/index.html">5.7.0-M1</a>
<a class="version is-missing" href="../../../5.6.4/index.html">5.6.4-SNAPSHOT</a>
<a class="version is-missing" href="../../../index.html">5.6.3</a>
<a class="version is-missing" href="../../../5.6.2/index.html">5.6.2</a>
<a class="version is-missing" href="../../../5.6.1/index.html">5.6.1</a>
<a class="version is-missing" href="../../../5.6.0/index.html">5.6.0</a>
<a class="version is-current" href="oauth2-resourceserver.html">5.6.0-RC1</a>
</div>
</div>
<div class="edit-this-page"><a href="https://github.com/spring-projects/spring-security/blob/5.6.0-RC1/docs/modules/ROOT/pages/servlet/oauth2/oauth2-resourceserver.adoc">Edit this Page</a></div>
</div>
<div class="content">
<aside class="toc sidebar" data-title="Contents" data-levels="2">
<div class="toc-menu"></div>
</aside>
<article class="doc">
<div class="admonitionblock important">
<table>
<tbody><tr>
<td class="icon">
<i class="fa icon-important" title="Important"></i>
</td>
<td class="content">
<div class="paragraph">
<p> For the latest stable version, please use <a href="../../../index.html">Spring Security 5.6.3</a>!</p>
</div>
</td>
</tr></tbody>
</table>
</div>
<h1 id="page-title" class="page">OAuth 2.0 Resource Server</h1>
<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>Spring Security supports protecting endpoints using two forms of OAuth 2.0 <a href="https://tools.ietf.org/html/rfc6750.html">Bearer Tokens</a>:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="https://tools.ietf.org/html/rfc7519">JWT</a></p>
</li>
<li>
<p>Opaque Tokens</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>This is handy in circumstances where an application has delegated its authority management to an <a href="https://tools.ietf.org/html/rfc6749">authorization server</a> (for example, Okta or Ping Identity).
This authorization server can be consulted by resource servers to authorize requests.</p>
</div>
<div class="paragraph">
<p>This section provides details on how Spring Security provides support for OAuth 2.0 <a href="https://tools.ietf.org/html/rfc6750.html">Bearer Tokens</a>.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>Working samples for both <a href="https://github.com/spring-projects/spring-security-samples/tree/main/servlet/spring-boot/java/oauth2/resource-server/jwe">JWTs</a> and <a href="https://github.com/spring-projects/spring-security-samples/tree/main/servlet/spring-boot/java/oauth2/resource-server/opaque">Opaque Tokens</a> are available in the <a href="https://github.com/spring-projects/spring-security-samples/tree/main">Spring Security Samples repository</a>.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Let&#8217;s take a look at how Bearer Token Authentication works within Spring Security.
First, we see that, like <a href="../authentication/passwords/basic.html#servlet-authentication-basic" class="xref page">Basic Authentication</a>, the <a href="https://tools.ietf.org/html/rfc7235#section-4.1">WWW-Authenticate</a> header is sent back to an unauthenticated client.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="../../_images/servlet/oauth2/bearerauthenticationentrypoint.png" alt="bearerauthenticationentrypoint">
</div>
<div class="title">Figure 1. Sending WWW-Authenticate Header</div>
</div>
<div class="paragraph">
<p>The figure above builds off our <a href="../architecture.html#servlet-securityfilterchain" class="xref page"><code>SecurityFilterChain</code></a> diagram.</p>
</div>
<div class="paragraph">
<p><span class="image"><img src="../../_images/icons/number_1.png" alt="number 1"></span> First, a user makes an unauthenticated request to the resource <code>/private</code> for which it is not authorized.</p>
</div>
<div class="paragraph">
<p><span class="image"><img src="../../_images/icons/number_2.png" alt="number 2"></span> Spring Security&#8217;s <a href="../authorization/authorize-requests.html#servlet-authorization-filtersecurityinterceptor" class="xref page"><code>FilterSecurityInterceptor</code></a> indicates that the unauthenticated request is <em>Denied</em> by throwing an <code>AccessDeniedException</code>.</p>
</div>
<div class="paragraph">
<p><span class="image"><img src="../../_images/icons/number_3.png" alt="number 3"></span> Since the user is not authenticated, <a href="../architecture.html#servlet-exceptiontranslationfilter" class="xref page"><code>ExceptionTranslationFilter</code></a> initiates <em>Start Authentication</em>.
The configured <a href="../authentication/architecture.html#servlet-authentication-authenticationentrypoint" class="xref page"><code>AuthenticationEntryPoint</code></a> is an instance of <a href="https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/oauth2/server/resource/web/BearerTokenAuthenticationEntryPoint.html"><code>BearerTokenAuthenticationEntryPoint</code></a> which sends a WWW-Authenticate header.
The <code>RequestCache</code> is typically a <code>NullRequestCache</code> that does not save the request since the client is capable of replaying the requests it originally requested.</p>
</div>
<div class="paragraph">
<p>When a client receives the <code>WWW-Authenticate: Bearer</code> header, it knows it should retry with a bearer token.
Below is the flow for the bearer token being processed.</p>
</div>
<div id="oauth2resourceserver-authentication-bearertokenauthenticationfilter" class="imageblock">
<div class="content">
<img src="../../_images/servlet/oauth2/bearertokenauthenticationfilter.png" alt="bearertokenauthenticationfilter">
</div>
<div class="title">Figure 2. Authenticating Bearer Token</div>
</div>
<div class="paragraph">
<p>The figure builds off our <a href="../architecture.html#servlet-securityfilterchain" class="xref page"><code>SecurityFilterChain</code></a> diagram.</p>
</div>
<div class="paragraph">
<p><span class="image"><img src="../../_images/icons/number_1.png" alt="number 1"></span> When the user submits their bearer token, the <code>BearerTokenAuthenticationFilter</code> creates a <code>BearerTokenAuthenticationToken</code> which is a type of <a href="../authentication/architecture.html#servlet-authentication-authentication" class="xref page"><code>Authentication</code></a> by extracting the token from the <code>HttpServletRequest</code>.</p>
</div>
<div class="paragraph">
<p><span class="image"><img src="../../_images/icons/number_2.png" alt="number 2"></span> Next, the <code>HttpServletRequest</code> is passed to the <code>AuthenticationManagerResolver</code>, which selects the <code>AuthenticationManager</code>. The <code>BearerTokenAuthenticationToken</code> is passed into the <code>AuthenticationManager</code> to be authenticated.
The details of what <code>AuthenticationManager</code> looks like depends on whether you&#8217;re configured for <a href="oauth2-resourceserver.html#oauth2resourceserver-jwt-minimalconfiguration">JWT</a> or <a href="oauth2-resourceserver.html#oauth2resourceserver-opaque-minimalconfiguration">opaque token</a>.</p>
</div>
<div class="paragraph">
<p><span class="image"><img src="../../_images/icons/number_3.png" alt="number 3"></span> If authentication fails, then <em>Failure</em></p>
</div>
<div class="ulist">
<ul>
<li>
<p>The <a href="../authentication/architecture.html#servlet-authentication-securitycontextholder" class="xref page">SecurityContextHolder</a> is cleared out.</p>
</li>
<li>
<p>The <code>AuthenticationEntryPoint</code> is invoked to trigger the WWW-Authenticate header to be sent again.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p><span class="image"><img src="../../_images/icons/number_4.png" alt="number 4"></span> If authentication is successful, then <em>Success</em>.</p>
</div>
<div class="ulist">
<ul>
<li>
<p>The <a href="../authentication/architecture.html#servlet-authentication-authentication" class="xref page">Authentication</a> is set on the <a href="../authentication/architecture.html#servlet-authentication-securitycontextholder" class="xref page">SecurityContextHolder</a>.</p>
</li>
<li>
<p>The <code>BearerTokenAuthenticationFilter</code> invokes <code>FilterChain.doFilter(request,response)</code> to continue with the rest of the application logic.</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="oauth2resourceserver-jwt-minimaldependencies"><a class="anchor" href="oauth2-resourceserver.html#oauth2resourceserver-jwt-minimaldependencies"></a>Minimal Dependencies for JWT</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Most Resource Server support is collected into <code>spring-security-oauth2-resource-server</code>.
However, the support for decoding and verifying JWTs is in <code>spring-security-oauth2-jose</code>, meaning that both are necessary in order to have a working resource server that supports JWT-encoded Bearer Tokens.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="oauth2resourceserver-jwt-minimalconfiguration"><a class="anchor" href="oauth2-resourceserver.html#oauth2resourceserver-jwt-minimalconfiguration"></a>Minimal Configuration for JWTs</h2>
<div class="sectionbody">
<div class="paragraph">
<p>When using <a href="https://spring.io/projects/spring-boot">Spring Boot</a>, configuring an application as a resource server consists of two basic steps.
First, include the needed dependencies and second, indicate the location of the authorization server.</p>
</div>
<div class="sect2">
<h3 id="_specifying_the_authorization_server"><a class="anchor" href="oauth2-resourceserver.html#_specifying_the_authorization_server"></a>Specifying the Authorization Server</h3>
<div class="paragraph">
<p>In a Spring Boot application, to specify which authorization server to use, simply do:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-yml hljs" data-lang="yml">spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: https://idp.example.com/issuer</code></pre>
</div>
</div>
<div class="paragraph">
<p>Where <code><a href="https://idp.example.com/issuer" class="bare">https://idp.example.com/issuer</a></code> is the value contained in the <code>iss</code> claim for JWT tokens that the authorization server will issue.
Resource Server will use this property to further self-configure, discover the authorization server&#8217;s public keys, and subsequently validate incoming JWTs.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
To use the <code>issuer-uri</code> property, it must also be true that one of <code><a href="https://idp.example.com/issuer/.well-known/openid-configuration" class="bare">https://idp.example.com/issuer/.well-known/openid-configuration</a></code>, <code><a href="https://idp.example.com/.well-known/openid-configuration/issuer" class="bare">https://idp.example.com/.well-known/openid-configuration/issuer</a></code>, or <code><a href="https://idp.example.com/.well-known/oauth-authorization-server/issuer" class="bare">https://idp.example.com/.well-known/oauth-authorization-server/issuer</a></code> is a supported endpoint for the authorization server.
This endpoint is referred to as a <a href="https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig">Provider Configuration</a> endpoint or a <a href="https://tools.ietf.org/html/rfc8414#section-3">Authorization Server Metadata</a> endpoint.
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>And that&#8217;s it!</p>
</div>
</div>
<div class="sect2">
<h3 id="_startup_expectations"><a class="anchor" href="oauth2-resourceserver.html#_startup_expectations"></a>Startup Expectations</h3>
<div class="paragraph">
<p>When this property and these dependencies are used, Resource Server will automatically configure itself to validate JWT-encoded Bearer Tokens.</p>
</div>
<div class="paragraph">
<p>It achieves this through a deterministic startup process:</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>Query the Provider Configuration or Authorization Server Metadata endpoint for the <code>jwks_url</code> property</p>
</li>
<li>
<p>Query the <code>jwks_url</code> endpoint for supported algorithms</p>
</li>
<li>
<p>Configure the validation strategy to query <code>jwks_url</code> for valid public keys of the algorithms found</p>
</li>
<li>
<p>Configure the validation strategy to validate each JWTs <code>iss</code> claim against <code><a href="https://idp.example.com" class="bare">https://idp.example.com</a></code>.</p>
</li>
</ol>
</div>
<div class="paragraph">
<p>A consequence of this process is that the authorization server must be up and receiving requests in order for Resource Server to successfully start up.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
If the authorization server is down when Resource Server queries it (given appropriate timeouts), then startup will fail.
</td>
</tr>
</table>
</div>
</div>
<div class="sect2">
<h3 id="_runtime_expectations"><a class="anchor" href="oauth2-resourceserver.html#_runtime_expectations"></a>Runtime Expectations</h3>
<div class="paragraph">
<p>Once the application is started up, Resource Server will attempt to process any request containing an <code>Authorization: Bearer</code> header:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-html hljs" data-lang="html">GET / HTTP/1.1
Authorization: Bearer some-token-value # Resource Server will process this</code></pre>
</div>
</div>
<div class="paragraph">
<p>So long as this scheme is indicated, Resource Server will attempt to process the request according to the Bearer Token specification.</p>
</div>
<div class="paragraph">
<p>Given a well-formed JWT, Resource Server will:</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>Validate its signature against a public key obtained from the <code>jwks_url</code> endpoint during startup and matched against the JWT</p>
</li>
<li>
<p>Validate the JWT&#8217;s <code>exp</code> and <code>nbf</code> timestamps and the JWT&#8217;s <code>iss</code> claim, and</p>
</li>
<li>
<p>Map each scope to an authority with the prefix <code>SCOPE_</code>.</p>
</li>
</ol>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
As the authorization server makes available new keys, Spring Security will automatically rotate the keys used to validate JWTs.
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>The resulting <code>Authentication#getPrincipal</code>, by default, is a Spring Security <code>Jwt</code> object, and <code>Authentication#getName</code> maps to the JWT&#8217;s <code>sub</code> property, if one is present.</p>
</div>
<div class="paragraph">
<p>From here, consider jumping to:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="oauth2-resourceserver.html#oauth2resourceserver-jwt-architecture">How JWT Authentication Works</a></p>
</li>
<li>
<p><a href="oauth2-resourceserver.html#oauth2resourceserver-jwt-jwkseturi">How to Configure without tying Resource Server startup to an authorization server&#8217;s availability</a></p>
</li>
<li>
<p><a href="oauth2-resourceserver.html#oauth2resourceserver-jwt-sansboot">How to Configure without Spring Boot</a></p>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="oauth2resourceserver-jwt-architecture"><a class="anchor" href="oauth2-resourceserver.html#oauth2resourceserver-jwt-architecture"></a>How JWT Authentication Works</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Next, let&#8217;s see the architectural components that Spring Security uses to support <a href="https://tools.ietf.org/html/rfc7519">JWT</a> Authentication in servlet-based applications, like the one we just saw.</p>
</div>
<div class="paragraph">
<p><a href="https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/oauth2/server/resource/authentication/JwtAuthenticationProvider.html"><code>JwtAuthenticationProvider</code></a> is an <a href="../authentication/architecture.html#servlet-authentication-authenticationprovider" class="xref page"><code>AuthenticationProvider</code></a> implementation that leverages a <a href="oauth2-resourceserver.html#oauth2resourceserver-jwt-decoder"><code>JwtDecoder</code></a> and <a href="oauth2-resourceserver.html#oauth2resourceserver-jwt-authorization-extraction"><code>JwtAuthenticationConverter</code></a> to authenticate a JWT.</p>
</div>
<div class="paragraph">
<p>Let&#8217;s take a look at how <code>JwtAuthenticationProvider</code> works within Spring Security.
The figure explains details of how the <a href="../authentication/architecture.html#servlet-authentication-authenticationmanager" class="xref page"><code>AuthenticationManager</code></a> in figures from <a href="oauth2-resourceserver.html#oauth2resourceserver-authentication-bearertokenauthenticationfilter">Reading the Bearer Token</a> works.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="../../_images/servlet/oauth2/jwtauthenticationprovider.png" alt="jwtauthenticationprovider">
</div>
<div class="title">Figure 3. <code>JwtAuthenticationProvider</code> Usage</div>
</div>
<div class="paragraph">
<p><span class="image"><img src="../../_images/icons/number_1.png" alt="number 1"></span> The authentication <code>Filter</code> from <a href="oauth2-resourceserver.html#oauth2resourceserver-authentication-bearertokenauthenticationfilter">Reading the Bearer Token</a> passes a <code>BearerTokenAuthenticationToken</code> to the <code>AuthenticationManager</code> which is implemented by <a href="../authentication/architecture.html#servlet-authentication-providermanager" class="xref page"><code>ProviderManager</code></a>.</p>
</div>
<div class="paragraph">
<p><span class="image"><img src="../../_images/icons/number_2.png" alt="number 2"></span> The <code>ProviderManager</code> is configured to use an <a href="../authentication/architecture.html#servlet-authentication-authenticationprovider" class="xref page">AuthenticationProvider</a> of type <code>JwtAuthenticationProvider</code>.</p>
</div>
<div id="oauth2resourceserver-jwt-architecture-jwtdecoder" class="paragraph">
<p><span class="image"><img src="../../_images/icons/number_3.png" alt="number 3"></span> <code>JwtAuthenticationProvider</code> decodes, verifies, and validates the <code>Jwt</code> using a <a href="oauth2-resourceserver.html#oauth2resourceserver-jwt-decoder"><code>JwtDecoder</code></a>.</p>
</div>
<div id="oauth2resourceserver-jwt-architecture-jwtauthenticationconverter" class="paragraph">
<p><span class="image"><img src="../../_images/icons/number_4.png" alt="number 4"></span> <code>JwtAuthenticationProvider</code> then uses the <a href="oauth2-resourceserver.html#oauth2resourceserver-jwt-authorization-extraction"><code>JwtAuthenticationConverter</code></a> to convert the <code>Jwt</code> into a <code>Collection</code> of granted authorities.</p>
</div>
<div class="paragraph">
<p><span class="image"><img src="../../_images/icons/number_5.png" alt="number 5"></span> When authentication is successful, the <a href="../authentication/architecture.html#servlet-authentication-authentication" class="xref page"><code>Authentication</code></a> that is returned is of type <code>JwtAuthenticationToken</code> and has a principal that is the <code>Jwt</code> returned by the configured <code>JwtDecoder</code>.
Ultimately, the returned <code>JwtAuthenticationToken</code> will be set on the <a href="../authentication/architecture.html#servlet-authentication-securitycontextholder" class="xref page"><code>SecurityContextHolder</code></a> by the authentication <code>Filter</code>.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="oauth2resourceserver-jwt-jwkseturi"><a class="anchor" href="oauth2-resourceserver.html#oauth2resourceserver-jwt-jwkseturi"></a>Specifying the Authorization Server JWK Set Uri Directly</h2>
<div class="sectionbody">
<div class="paragraph">
<p>If the authorization server doesn&#8217;t support any configuration endpoints, or if Resource Server must be able to start up independently from the authorization server, then the <code>jwk-set-uri</code> can be supplied as well:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-yaml hljs" data-lang="yaml">spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: https://idp.example.com
          jwk-set-uri: https://idp.example.com/.well-known/jwks.json</code></pre>
</div>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
The JWK Set uri is not standardized, but can typically be found in the authorization server&#8217;s documentation
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Consequently, Resource Server will not ping the authorization server at startup.
We still specify the <code>issuer-uri</code> so that Resource Server still validates the <code>iss</code> claim on incoming JWTs.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
This property can also be supplied directly on the <a href="oauth2-resourceserver.html#oauth2resourceserver-jwt-jwkseturi-dsl">DSL</a>.
</td>
</tr>
</table>
</div>
</div>
</div>
<div class="sect1">
<h2 id="oauth2resourceserver-jwt-sansboot"><a class="anchor" href="oauth2-resourceserver.html#oauth2resourceserver-jwt-sansboot"></a>Overriding or Replacing Boot Auto Configuration</h2>
<div class="sectionbody">
<div class="paragraph">
<p>There are two <code>@Bean</code>s that Spring Boot generates on Resource Server&#8217;s behalf.</p>
</div>
<div class="paragraph">
<p>The first is a <code>WebSecurityConfigurerAdapter</code> that configures the app as a resource server. When including <code>spring-security-oauth2-jose</code>, this <code>WebSecurityConfigurerAdapter</code> looks like:</p>
</div>
<div class="exampleblock">
<div class="title">Example 1. Default JWT Configuration</div>
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">protected void configure(HttpSecurity http) {
    http
        .authorizeRequests(authorize -&gt; authorize
            .anyRequest().authenticated()
        )
        .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt);
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">fun configure(http: HttpSecurity) {
    http {
        authorizeRequests {
            authorize(anyRequest, authenticated)
        }
        oauth2ResourceServer {
            jwt { }
        }
    }
}</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>If the application doesn&#8217;t expose a <code>WebSecurityConfigurerAdapter</code> bean, then Spring Boot will expose the above default one.</p>
</div>
<div class="paragraph">
<p>Replacing this is as simple as exposing the bean within the application:</p>
</div>
<div class="exampleblock">
<div class="title">Example 2. Custom JWT Configuration</div>
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@EnableWebSecurity
public class MyCustomSecurityConfiguration extends WebSecurityConfigurerAdapter {
    protected void configure(HttpSecurity http) {
        http
            .authorizeRequests(authorize -&gt; authorize
                .mvcMatchers("/messages/**").hasAuthority("SCOPE_message:read")
                .anyRequest().authenticated()
            )
            .oauth2ResourceServer(oauth2 -&gt; oauth2
                .jwt(jwt -&gt; jwt
                    .jwtAuthenticationConverter(myConverter())
                )
            );
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">@EnableWebSecurity
class MyCustomSecurityConfiguration : WebSecurityConfigurerAdapter() {
    override fun configure(http: HttpSecurity) {
        http {
            authorizeRequests {
                authorize("/messages/**", hasAuthority("SCOPE_message:read"))
                authorize(anyRequest, authenticated)
            }
            oauth2ResourceServer {
                jwt {
                    jwtAuthenticationConverter = myConverter()
                }
            }
        }
    }
}</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>The above requires the scope of <code>message:read</code> for any URL that starts with <code>/messages/</code>.</p>
</div>
<div class="paragraph">
<p>Methods on the <code>oauth2ResourceServer</code> DSL will also override or replace auto configuration.</p>
</div>
<div id="oauth2resourceserver-jwt-decoder" class="paragraph">
<p>For example, the second <code>@Bean</code> Spring Boot creates is a <code>JwtDecoder</code>, which <a href="oauth2-resourceserver.html#oauth2resourceserver-jwt-architecture-jwtdecoder">decodes <code>String</code> tokens into validated instances of <code>Jwt</code></a>:</p>
</div>
<div class="exampleblock">
<div class="title">Example 3. JWT Decoder</div>
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Bean
public JwtDecoder jwtDecoder() {
    return JwtDecoders.fromIssuerLocation(issuerUri);
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">@Bean
fun jwtDecoder(): JwtDecoder {
    return JwtDecoders.fromIssuerLocation(issuerUri)
}</code></pre>
</div>
</div>
</div>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
Calling <code><a href="https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/oauth2/jwt/JwtDecoders.html#fromIssuerLocation-java.lang.String-">JwtDecoders#fromIssuerLocation</a></code> is what invokes the Provider Configuration or Authorization Server Metadata endpoint in order to derive the JWK Set Uri.
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>If the application doesn&#8217;t expose a <code>JwtDecoder</code> bean, then Spring Boot will expose the above default one.</p>
</div>
<div class="paragraph">
<p>And its configuration can be overridden using <code>jwkSetUri()</code> or replaced using <code>decoder()</code>.</p>
</div>
<div class="paragraph">
<p>Or, if you&#8217;re not using Spring Boot at all, then both of these components - the filter chain and a <code>JwtDecoder</code> can be specified in XML.</p>
</div>
<div class="paragraph">
<p>The filter chain is specified like so:</p>
</div>
<div class="exampleblock">
<div class="title">Example 4. Default JWT Configuration</div>
<div class="content">
<div class="listingblock primary">
<div class="title">Xml</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml">&lt;http&gt;
    &lt;intercept-uri pattern="/**" access="authenticated"/&gt;
    &lt;oauth2-resource-server&gt;
        &lt;jwt decoder-ref="jwtDecoder"/&gt;
    &lt;/oauth2-resource-server&gt;
&lt;/http&gt;</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>And the <code>JwtDecoder</code> like so:</p>
</div>
<div class="exampleblock">
<div class="title">Example 5. JWT Decoder</div>
<div class="content">
<div class="listingblock primary">
<div class="title">Xml</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml">&lt;bean id="jwtDecoder"
        class="org.springframework.security.oauth2.jwt.JwtDecoders"
        factory-method="fromIssuerLocation"&gt;
    &lt;constructor-arg value="${spring.security.oauth2.resourceserver.jwt.jwk-set-uri}"/&gt;
&lt;/bean&gt;</code></pre>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="oauth2resourceserver-jwt-jwkseturi-dsl"><a class="anchor" href="oauth2-resourceserver.html#oauth2resourceserver-jwt-jwkseturi-dsl"></a>Using <code>jwkSetUri()</code></h3>
<div class="paragraph">
<p>An authorization server&#8217;s JWK Set Uri can be configured <a href="oauth2-resourceserver.html#oauth2resourceserver-jwt-jwkseturi">as a configuration property</a> or it can be supplied in the DSL:</p>
</div>
<div class="exampleblock">
<div class="title">Example 6. JWK Set Uri Configuration</div>
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@EnableWebSecurity
public class DirectlyConfiguredJwkSetUri extends WebSecurityConfigurerAdapter {
    protected void configure(HttpSecurity http) {
        http
            .authorizeRequests(authorize -&gt; authorize
                .anyRequest().authenticated()
            )
            .oauth2ResourceServer(oauth2 -&gt; oauth2
                .jwt(jwt -&gt; jwt
                    .jwkSetUri("https://idp.example.com/.well-known/jwks.json")
                )
            );
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">@EnableWebSecurity
class DirectlyConfiguredJwkSetUri : WebSecurityConfigurerAdapter() {
    override fun configure(http: HttpSecurity) {
        http {
            authorizeRequests {
                authorize(anyRequest, authenticated)
            }
            oauth2ResourceServer {
                jwt {
                    jwkSetUri = "https://idp.example.com/.well-known/jwks.json"
                }
            }
        }
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Xml</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml">&lt;http&gt;
    &lt;intercept-uri pattern="/**" access="authenticated"/&gt;
    &lt;oauth2-resource-server&gt;
        &lt;jwt jwk-set-uri="https://idp.example.com/.well-known/jwks.json"/&gt;
    &lt;/oauth2-resource-server&gt;
&lt;/http&gt;</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>Using <code>jwkSetUri()</code> takes precedence over any configuration property.</p>
</div>
</div>
<div class="sect2">
<h3 id="oauth2resourceserver-jwt-decoder-dsl"><a class="anchor" href="oauth2-resourceserver.html#oauth2resourceserver-jwt-decoder-dsl"></a>Using <code>decoder()</code></h3>
<div class="paragraph">
<p>More powerful than <code>jwkSetUri()</code> is <code>decoder()</code>, which will completely replace any Boot auto configuration of <a href="oauth2-resourceserver.html#oauth2resourceserver-jwt-architecture-jwtdecoder"><code>JwtDecoder</code></a>:</p>
</div>
<div class="exampleblock">
<div class="title">Example 7. JWT Decoder Configuration</div>
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@EnableWebSecurity
public class DirectlyConfiguredJwtDecoder extends WebSecurityConfigurerAdapter {
    protected void configure(HttpSecurity http) {
        http
            .authorizeRequests(authorize -&gt; authorize
                .anyRequest().authenticated()
            )
            .oauth2ResourceServer(oauth2 -&gt; oauth2
                .jwt(jwt -&gt; jwt
                    .decoder(myCustomDecoder())
                )
            );
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">@EnableWebSecurity
class DirectlyConfiguredJwtDecoder : WebSecurityConfigurerAdapter() {
    override fun configure(http: HttpSecurity) {
        http {
            authorizeRequests {
                authorize(anyRequest, authenticated)
            }
            oauth2ResourceServer {
                jwt {
                    jwtDecoder = myCustomDecoder()
                }
            }
        }
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Xml</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml">&lt;http&gt;
    &lt;intercept-uri pattern="/**" access="authenticated"/&gt;
    &lt;oauth2-resource-server&gt;
        &lt;jwt decoder-ref="myCustomDecoder"/&gt;
    &lt;/oauth2-resource-server&gt;
&lt;/http&gt;</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>This is handy when deeper configuration, like <a href="oauth2-resourceserver.html#oauth2resourceserver-jwt-validation">validation</a>, <a href="oauth2-resourceserver.html#oauth2resourceserver-jwt-claimsetmapping">mapping</a>, or <a href="oauth2-resourceserver.html#oauth2resourceserver-jwt-timeouts">request timeouts</a>, is necessary.</p>
</div>
</div>
<div class="sect2">
<h3 id="oauth2resourceserver-jwt-decoder-bean"><a class="anchor" href="oauth2-resourceserver.html#oauth2resourceserver-jwt-decoder-bean"></a>Exposing a <code>JwtDecoder</code> <code>@Bean</code></h3>
<div class="paragraph">
<p>Or, exposing a <a href="oauth2-resourceserver.html#oauth2resourceserver-jwt-architecture-jwtdecoder"><code>JwtDecoder</code></a> <code>@Bean</code> has the same effect as <code>decoder()</code>:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Bean
public JwtDecoder jwtDecoder() {
    return NimbusJwtDecoder.withJwkSetUri(jwkSetUri).build();
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">@Bean
fun jwtDecoder(): JwtDecoder {
    return NimbusJwtDecoder.withJwkSetUri(jwkSetUri).build()
}</code></pre>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="oauth2resourceserver-jwt-decoder-algorithm"><a class="anchor" href="oauth2-resourceserver.html#oauth2resourceserver-jwt-decoder-algorithm"></a>Configuring Trusted Algorithms</h2>
<div class="sectionbody">
<div class="paragraph">
<p>By default, <code>NimbusJwtDecoder</code>, and hence Resource Server, will only trust and verify tokens using <code>RS256</code>.</p>
</div>
<div class="paragraph">
<p>You can customize this via <a href="oauth2-resourceserver.html#oauth2resourceserver-jwt-boot-algorithm">Spring Boot</a>, <a href="oauth2-resourceserver.html#oauth2resourceserver-jwt-decoder-builder">the NimbusJwtDecoder builder</a>, or from the <a href="oauth2-resourceserver.html#oauth2resourceserver-jwt-decoder-jwk-response">JWK Set response</a>.</p>
</div>
<div class="sect2">
<h3 id="oauth2resourceserver-jwt-boot-algorithm"><a class="anchor" href="oauth2-resourceserver.html#oauth2resourceserver-jwt-boot-algorithm"></a>Via Spring Boot</h3>
<div class="paragraph">
<p>The simplest way to set the algorithm is as a property:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-yaml hljs" data-lang="yaml">spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          jws-algorithm: RS512
          jwk-set-uri: https://idp.example.org/.well-known/jwks.json</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="oauth2resourceserver-jwt-decoder-builder"><a class="anchor" href="oauth2-resourceserver.html#oauth2resourceserver-jwt-decoder-builder"></a>Using a Builder</h3>
<div class="paragraph">
<p>For greater power, though, we can use a builder that ships with <code>NimbusJwtDecoder</code>:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Bean
JwtDecoder jwtDecoder() {
    return NimbusJwtDecoder.withJwkSetUri(this.jwkSetUri)
            .jwsAlgorithm(RS512).build();
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">@Bean
fun jwtDecoder(): JwtDecoder {
    return NimbusJwtDecoder.withJwkSetUri(this.jwkSetUri)
            .jwsAlgorithm(RS512).build()
}</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>Calling <code>jwsAlgorithm</code> more than once will configure <code>NimbusJwtDecoder</code> to trust more than one algorithm, like so:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Bean
JwtDecoder jwtDecoder() {
    return NimbusJwtDecoder.withJwkSetUri(this.jwkSetUri)
            .jwsAlgorithm(RS512).jwsAlgorithm(ES512).build();
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">@Bean
fun jwtDecoder(): JwtDecoder {
    return NimbusJwtDecoder.withJwkSetUri(this.jwkSetUri)
            .jwsAlgorithm(RS512).jwsAlgorithm(ES512).build()
}</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>Or, you can call <code>jwsAlgorithms</code>:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Bean
JwtDecoder jwtDecoder() {
    return NimbusJwtDecoder.withJwkSetUri(this.jwkSetUri)
            .jwsAlgorithms(algorithms -&gt; {
                    algorithms.add(RS512);
                    algorithms.add(ES512);
            }).build();
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">@Bean
fun jwtDecoder(): JwtDecoder {
    return NimbusJwtDecoder.withJwkSetUri(this.jwkSetUri)
            .jwsAlgorithms {
                it.add(RS512)
                it.add(ES512)
            }.build()
}</code></pre>
</div>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="oauth2resourceserver-jwt-decoder-jwk-response"><a class="anchor" href="oauth2-resourceserver.html#oauth2resourceserver-jwt-decoder-jwk-response"></a>From JWK Set response</h3>
<div class="paragraph">
<p>Since Spring Security&#8217;s JWT support is based off of Nimbus, you can use all it&#8217;s great features as well.</p>
</div>
<div class="paragraph">
<p>For example, Nimbus has a <code>JWSKeySelector</code> implementation that will select the set of algorithms based on the JWK Set URI response.
You can use it to generate a <code>NimbusJwtDecoder</code> like so:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Bean
public JwtDecoder jwtDecoder() {
    // makes a request to the JWK Set endpoint
    JWSKeySelector&lt;SecurityContext&gt; jwsKeySelector =
            JWSAlgorithmFamilyJWSKeySelector.fromJWKSetURL(this.jwkSetUrl);

    DefaultJWTProcessor&lt;SecurityContext&gt; jwtProcessor =
            new DefaultJWTProcessor&lt;&gt;();
    jwtProcessor.setJWSKeySelector(jwsKeySelector);

    return new NimbusJwtDecoder(jwtProcessor);
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">@Bean
fun jwtDecoder(): JwtDecoder {
    // makes a request to the JWK Set endpoint
    val jwsKeySelector: JWSKeySelector&lt;SecurityContext&gt; = JWSAlgorithmFamilyJWSKeySelector.fromJWKSetURL&lt;SecurityContext&gt;(this.jwkSetUrl)
    val jwtProcessor: DefaultJWTProcessor&lt;SecurityContext&gt; = DefaultJWTProcessor()
    jwtProcessor.jwsKeySelector = jwsKeySelector
    return NimbusJwtDecoder(jwtProcessor)
}</code></pre>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="oauth2resourceserver-jwt-decoder-public-key"><a class="anchor" href="oauth2-resourceserver.html#oauth2resourceserver-jwt-decoder-public-key"></a>Trusting a Single Asymmetric Key</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Simpler than backing a Resource Server with a JWK Set endpoint is to hard-code an RSA public key.
The public key can be provided via <a href="oauth2-resourceserver.html#oauth2resourceserver-jwt-decoder-public-key-boot">Spring Boot</a> or by <a href="oauth2-resourceserver.html#oauth2resourceserver-jwt-decoder-public-key-builder">Using a Builder</a>.</p>
</div>
<div class="sect2">
<h3 id="oauth2resourceserver-jwt-decoder-public-key-boot"><a class="anchor" href="oauth2-resourceserver.html#oauth2resourceserver-jwt-decoder-public-key-boot"></a>Via Spring Boot</h3>
<div class="paragraph">
<p>Specifying a key via Spring Boot is quite simple.
The key&#8217;s location can be specified like so:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-yaml hljs" data-lang="yaml">spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          public-key-location: classpath:my-key.pub</code></pre>
</div>
</div>
<div class="paragraph">
<p>Or, to allow for a more sophisticated lookup, you can post-process the <code>RsaKeyConversionServicePostProcessor</code>:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Bean
BeanFactoryPostProcessor conversionServiceCustomizer() {
    return beanFactory -&gt;
        beanFactory.getBean(RsaKeyConversionServicePostProcessor.class)
                .setResourceLoader(new CustomResourceLoader());
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">@Bean
fun conversionServiceCustomizer(): BeanFactoryPostProcessor {
    return BeanFactoryPostProcessor { beanFactory -&gt;
        beanFactory.getBean&lt;RsaKeyConversionServicePostProcessor&gt;()
                .setResourceLoader(CustomResourceLoader())
    }
}</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>Specify your key&#8217;s location:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-yaml hljs" data-lang="yaml">key.location: hfds://my-key.pub</code></pre>
</div>
</div>
<div class="paragraph">
<p>And then autowire the value:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Value("${key.location}")
RSAPublicKey key;</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">@Value("\${key.location}")
val key: RSAPublicKey? = null</code></pre>
</div>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="oauth2resourceserver-jwt-decoder-public-key-builder"><a class="anchor" href="oauth2-resourceserver.html#oauth2resourceserver-jwt-decoder-public-key-builder"></a>Using a Builder</h3>
<div class="paragraph">
<p>To wire an <code>RSAPublicKey</code> directly, you can simply use the appropriate <code>NimbusJwtDecoder</code> builder, like so:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Bean
public JwtDecoder jwtDecoder() {
    return NimbusJwtDecoder.withPublicKey(this.key).build();
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">@Bean
fun jwtDecoder(): JwtDecoder {
    return NimbusJwtDecoder.withPublicKey(this.key).build()
}</code></pre>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="oauth2resourceserver-jwt-decoder-secret-key"><a class="anchor" href="oauth2-resourceserver.html#oauth2resourceserver-jwt-decoder-secret-key"></a>Trusting a Single Symmetric Key</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Using a single symmetric key is also simple.
You can simply load in your <code>SecretKey</code> and use the appropriate <code>NimbusJwtDecoder</code> builder, like so:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Bean
public JwtDecoder jwtDecoder() {
    return NimbusJwtDecoder.withSecretKey(this.key).build();
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">@Bean
fun jwtDecoder(): JwtDecoder {
    return NimbusJwtDecoder.withSecretKey(key).build()
}</code></pre>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="oauth2resourceserver-jwt-authorization"><a class="anchor" href="oauth2-resourceserver.html#oauth2resourceserver-jwt-authorization"></a>Configuring Authorization</h2>
<div class="sectionbody">
<div class="paragraph">
<p>A JWT that is issued from an OAuth 2.0 Authorization Server will typically either have a <code>scope</code> or <code>scp</code> attribute, indicating the scopes (or authorities) it&#8217;s been granted, for example:</p>
</div>
<div class="paragraph">
<p><code>{ &#8230;&#8203;, "scope" : "messages contacts"}</code></p>
</div>
<div class="paragraph">
<p>When this is the case, Resource Server will attempt to coerce these scopes into a list of granted authorities, prefixing each scope with the string "SCOPE_".</p>
</div>
<div class="paragraph">
<p>This means that to protect an endpoint or method with a scope derived from a JWT, the corresponding expressions should include this prefix:</p>
</div>
<div class="exampleblock">
<div class="title">Example 8. Authorization Configuration</div>
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@EnableWebSecurity
public class DirectlyConfiguredJwkSetUri extends WebSecurityConfigurerAdapter {
    protected void configure(HttpSecurity http) {
        http
            .authorizeRequests(authorize -&gt; authorize
                .mvcMatchers("/contacts/**").hasAuthority("SCOPE_contacts")
                .mvcMatchers("/messages/**").hasAuthority("SCOPE_messages")
                .anyRequest().authenticated()
            )
            .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt);
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">@EnableWebSecurity
class DirectlyConfiguredJwkSetUri : WebSecurityConfigurerAdapter() {
    override fun configure(http: HttpSecurity) {
        http {
            authorizeRequests {
                authorize("/contacts/**", hasAuthority("SCOPE_contacts"))
                authorize("/messages/**", hasAuthority("SCOPE_messages"))
                authorize(anyRequest, authenticated)
            }
            oauth2ResourceServer {
                jwt { }
            }
        }
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Xml</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml">&lt;http&gt;
    &lt;intercept-uri pattern="/contacts/**" access="hasAuthority('SCOPE_contacts')"/&gt;
    &lt;intercept-uri pattern="/messages/**" access="hasAuthority('SCOPE_messages')"/&gt;
    &lt;oauth2-resource-server&gt;
        &lt;jwt jwk-set-uri="https://idp.example.org/.well-known/jwks.json"/&gt;
    &lt;/oauth2-resource-server&gt;
&lt;/http&gt;</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>Or similarly with method security:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@PreAuthorize("hasAuthority('SCOPE_messages')")
public List&lt;Message&gt; getMessages(...) {}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">@PreAuthorize("hasAuthority('SCOPE_messages')")
fun getMessages(): List&lt;Message&gt; { }</code></pre>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="oauth2resourceserver-jwt-authorization-extraction"><a class="anchor" href="oauth2-resourceserver.html#oauth2resourceserver-jwt-authorization-extraction"></a>Extracting Authorities Manually</h3>
<div class="paragraph">
<p>However, there are a number of circumstances where this default is insufficient.
For example, some authorization servers don&#8217;t use the <code>scope</code> attribute, but instead have their own custom attribute.
Or, at other times, the resource server may need to adapt the attribute or a composition of attributes into internalized authorities.</p>
</div>
<div class="paragraph">
<p>To this end, Spring Security ships with <code>JwtAuthenticationConverter</code>, which is responsible for <a href="oauth2-resourceserver.html#oauth2resourceserver-jwt-architecture-jwtauthenticationconverter">converting a <code>Jwt</code> into an <code>Authentication</code></a>.
By default, Spring Security will wire the <code>JwtAuthenticationProvider</code> with a default instance of <code>JwtAuthenticationConverter</code>.</p>
</div>
<div class="paragraph">
<p>As part of configuring a <code>JwtAuthenticationConverter</code>, you can supply a subsidiary converter to go from <code>Jwt</code> to a <code>Collection</code> of granted authorities.</p>
</div>
<div class="paragraph">
<p>Let&#8217;s say that that your authorization server communicates authorities in a custom claim called <code>authorities</code>.
In that case, you can configure the claim that <a href="oauth2-resourceserver.html#oauth2resourceserver-jwt-architecture-jwtauthenticationconverter"><code>JwtAuthenticationConverter</code></a> should inspect, like so:</p>
</div>
<div class="exampleblock">
<div class="title">Example 9. Authorities Claim Configuration</div>
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Bean
public JwtAuthenticationConverter jwtAuthenticationConverter() {
    JwtGrantedAuthoritiesConverter grantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
    grantedAuthoritiesConverter.setAuthoritiesClaimName("authorities");

    JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
    jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(grantedAuthoritiesConverter);
    return jwtAuthenticationConverter;
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">@Bean
fun jwtAuthenticationConverter(): JwtAuthenticationConverter {
    val grantedAuthoritiesConverter = JwtGrantedAuthoritiesConverter()
    grantedAuthoritiesConverter.setAuthoritiesClaimName("authorities")

    val jwtAuthenticationConverter = JwtAuthenticationConverter()
    jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(grantedAuthoritiesConverter)
    return jwtAuthenticationConverter
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Xml</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml">&lt;http&gt;
    &lt;intercept-uri pattern="/contacts/**" access="hasAuthority('SCOPE_contacts')"/&gt;
    &lt;intercept-uri pattern="/messages/**" access="hasAuthority('SCOPE_messages')"/&gt;
    &lt;oauth2-resource-server&gt;
        &lt;jwt jwk-set-uri="https://idp.example.org/.well-known/jwks.json"
                jwt-authentication-converter-ref="jwtAuthenticationConverter"/&gt;
    &lt;/oauth2-resource-server&gt;
&lt;/http&gt;

&lt;bean id="jwtAuthenticationConverter"
        class="org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter"&gt;
    &lt;property name="jwtGrantedAuthoritiesConverter" ref="jwtGrantedAuthoritiesConverter"/&gt;
&lt;/bean&gt;

&lt;bean id="jwtGrantedAuthoritiesConverter"
        class="org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter"&gt;
    &lt;property name="authoritiesClaimName" value="authorities"/&gt;
&lt;/bean&gt;</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>You can also configure the authority prefix to be different as well.
Instead of prefixing each authority with <code>SCOPE_</code>, you can change it to <code>ROLE_</code> like so:</p>
</div>
<div class="exampleblock">
<div class="title">Example 10. Authorities Prefix Configuration</div>
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Bean
public JwtAuthenticationConverter jwtAuthenticationConverter() {
    JwtGrantedAuthoritiesConverter grantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
    grantedAuthoritiesConverter.setAuthorityPrefix("ROLE_");

    JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
    jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(grantedAuthoritiesConverter);
    return jwtAuthenticationConverter;
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">@Bean
fun jwtAuthenticationConverter(): JwtAuthenticationConverter {
    val grantedAuthoritiesConverter = JwtGrantedAuthoritiesConverter()
    grantedAuthoritiesConverter.setAuthorityPrefix("ROLE_")

    val jwtAuthenticationConverter = JwtAuthenticationConverter()
    jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(grantedAuthoritiesConverter)
    return jwtAuthenticationConverter
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Xml</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml">&lt;http&gt;
    &lt;intercept-uri pattern="/contacts/**" access="hasAuthority('SCOPE_contacts')"/&gt;
    &lt;intercept-uri pattern="/messages/**" access="hasAuthority('SCOPE_messages')"/&gt;
    &lt;oauth2-resource-server&gt;
        &lt;jwt jwk-set-uri="https://idp.example.org/.well-known/jwks.json"
                jwt-authentication-converter-ref="jwtAuthenticationConverter"/&gt;
    &lt;/oauth2-resource-server&gt;
&lt;/http&gt;

&lt;bean id="jwtAuthenticationConverter"
        class="org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter"&gt;
    &lt;property name="jwtGrantedAuthoritiesConverter" ref="jwtGrantedAuthoritiesConverter"/&gt;
&lt;/bean&gt;

&lt;bean id="jwtGrantedAuthoritiesConverter"
        class="org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter"&gt;
    &lt;property name="authorityPrefix" value="ROLE_"/&gt;
&lt;/bean&gt;</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>Or, you can remove the prefix altogether by calling <code>JwtGrantedAuthoritiesConverter#setAuthorityPrefix("")</code>.</p>
</div>
<div class="paragraph">
<p>For more flexibility, the DSL supports entirely replacing the converter with any class that implements <code>Converter&lt;Jwt, AbstractAuthenticationToken&gt;</code>:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">static class CustomAuthenticationConverter implements Converter&lt;Jwt, AbstractAuthenticationToken&gt; {
    public AbstractAuthenticationToken convert(Jwt jwt) {
        return new CustomAuthenticationToken(jwt);
    }
}

// ...

@EnableWebSecurity
public class CustomAuthenticationConverterConfig extends WebSecurityConfigurerAdapter {
    protected void configure(HttpSecurity http) {
        http
            .authorizeRequests(authorize -&gt; authorize
                .anyRequest().authenticated()
            )
            .oauth2ResourceServer(oauth2 -&gt; oauth2
                .jwt(jwt -&gt; jwt
                    .jwtAuthenticationConverter(new CustomAuthenticationConverter())
                )
            );
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">internal class CustomAuthenticationConverter : Converter&lt;Jwt, AbstractAuthenticationToken&gt; {
    override fun convert(jwt: Jwt): AbstractAuthenticationToken {
        return CustomAuthenticationToken(jwt)
    }
}

// ...

@EnableWebSecurity
class CustomAuthenticationConverterConfig : WebSecurityConfigurerAdapter() {
    override fun configure(http: HttpSecurity) {
       http {
            authorizeRequests {
                authorize(anyRequest, authenticated)
            }
           oauth2ResourceServer {
               jwt {
                   jwtAuthenticationConverter = CustomAuthenticationConverter()
               }
           }
        }
    }
}</code></pre>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="oauth2resourceserver-jwt-validation"><a class="anchor" href="oauth2-resourceserver.html#oauth2resourceserver-jwt-validation"></a>Configuring Validation</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Using <a href="oauth2-resourceserver.html#oauth2resourceserver-jwt-minimalconfiguration">minimal Spring Boot configuration</a>, indicating the authorization server&#8217;s issuer uri, Resource Server will default to verifying the <code>iss</code> claim as well as the <code>exp</code> and <code>nbf</code> timestamp claims.</p>
</div>
<div class="paragraph">
<p>In circumstances where validation needs to be customized, Resource Server ships with two standard validators and also accepts custom <code>OAuth2TokenValidator</code> instances.</p>
</div>
<div class="sect2">
<h3 id="oauth2resourceserver-jwt-validation-clockskew"><a class="anchor" href="oauth2-resourceserver.html#oauth2resourceserver-jwt-validation-clockskew"></a>Customizing Timestamp Validation</h3>
<div class="paragraph">
<p>JWT&#8217;s typically have a window of validity, with the start of the window indicated in the <code>nbf</code> claim and the end indicated in the <code>exp</code> claim.</p>
</div>
<div class="paragraph">
<p>However, every server can experience clock drift, which can cause tokens to appear expired to one server, but not to another.
This can cause some implementation heartburn as the number of collaborating servers increases in a distributed system.</p>
</div>
<div class="paragraph">
<p>Resource Server uses <code>JwtTimestampValidator</code> to verify a token&#8217;s validity window, and it can be configured with a <code>clockSkew</code> to alleviate the above problem:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Bean
JwtDecoder jwtDecoder() {
     NimbusJwtDecoder jwtDecoder = (NimbusJwtDecoder)
             JwtDecoders.fromIssuerLocation(issuerUri);

     OAuth2TokenValidator&lt;Jwt&gt; withClockSkew = new DelegatingOAuth2TokenValidator&lt;&gt;(
            new JwtTimestampValidator(Duration.ofSeconds(60)),
            new JwtIssuerValidator(issuerUri));

     jwtDecoder.setJwtValidator(withClockSkew);

     return jwtDecoder;
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">@Bean
fun jwtDecoder(): JwtDecoder {
    val jwtDecoder: NimbusJwtDecoder = JwtDecoders.fromIssuerLocation(issuerUri) as NimbusJwtDecoder

    val withClockSkew: OAuth2TokenValidator&lt;Jwt&gt; = DelegatingOAuth2TokenValidator(
            JwtTimestampValidator(Duration.ofSeconds(60)),
            JwtIssuerValidator(issuerUri))

    jwtDecoder.setJwtValidator(withClockSkew)

    return jwtDecoder
}</code></pre>
</div>
</div>
</div>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
By default, Resource Server configures a clock skew of 60 seconds.
</td>
</tr>
</table>
</div>
</div>
<div class="sect2">
<h3 id="oauth2resourceserver-jwt-validation-custom"><a class="anchor" href="oauth2-resourceserver.html#oauth2resourceserver-jwt-validation-custom"></a>Configuring a Custom Validator</h3>
<div class="paragraph">
<p>Adding a check for the <code>aud</code> claim is simple with the <code>OAuth2TokenValidator</code> API:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">OAuth2TokenValidator&lt;Jwt&gt; audienceValidator() {
    return new JwtClaimValidator&lt;List&lt;String&gt;&gt;(AUD, aud -&gt; aud.contains("messaging"));
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">fun audienceValidator(): OAuth2TokenValidator&lt;Jwt?&gt; {
    return JwtClaimValidator&lt;List&lt;String&gt;&gt;(AUD) { aud -&gt; aud.contains("messaging") }
}</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>Or, for more control you can implement your own <code>OAuth2TokenValidator</code>:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">static class AudienceValidator implements OAuth2TokenValidator&lt;Jwt&gt; {
    OAuth2Error error = new OAuth2Error("custom_code", "Custom error message", null);

    @Override
    public OAuth2TokenValidatorResult validate(Jwt jwt) {
        if (jwt.getAudience().contains("messaging")) {
            return OAuth2TokenValidatorResult.success();
        } else {
            return OAuth2TokenValidatorResult.failure(error);
        }
    }
}

// ...

OAuth2TokenValidator&lt;Jwt&gt; audienceValidator() {
    return new AudienceValidator();
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">internal class AudienceValidator : OAuth2TokenValidator&lt;Jwt&gt; {
    var error: OAuth2Error = OAuth2Error("custom_code", "Custom error message", null)

    override fun validate(jwt: Jwt): OAuth2TokenValidatorResult {
        return if (jwt.audience.contains("messaging")) {
            OAuth2TokenValidatorResult.success()
        } else {
            OAuth2TokenValidatorResult.failure(error)
        }
    }
}

// ...

fun audienceValidator(): OAuth2TokenValidator&lt;Jwt&gt; {
    return AudienceValidator()
}</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>Then, to add into a resource server, it&#8217;s a matter of specifying the <a href="oauth2-resourceserver.html#oauth2resourceserver-jwt-architecture-jwtdecoder"><code>JwtDecoder</code></a> instance:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Bean
JwtDecoder jwtDecoder() {
    NimbusJwtDecoder jwtDecoder = (NimbusJwtDecoder)
        JwtDecoders.fromIssuerLocation(issuerUri);

    OAuth2TokenValidator&lt;Jwt&gt; audienceValidator = audienceValidator();
    OAuth2TokenValidator&lt;Jwt&gt; withIssuer = JwtValidators.createDefaultWithIssuer(issuerUri);
    OAuth2TokenValidator&lt;Jwt&gt; withAudience = new DelegatingOAuth2TokenValidator&lt;&gt;(withIssuer, audienceValidator);

    jwtDecoder.setJwtValidator(withAudience);

    return jwtDecoder;
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">@Bean
fun jwtDecoder(): JwtDecoder {
    val jwtDecoder: NimbusJwtDecoder = JwtDecoders.fromIssuerLocation(issuerUri) as NimbusJwtDecoder

    val audienceValidator = audienceValidator()
    val withIssuer: OAuth2TokenValidator&lt;Jwt&gt; = JwtValidators.createDefaultWithIssuer(issuerUri)
    val withAudience: OAuth2TokenValidator&lt;Jwt&gt; = DelegatingOAuth2TokenValidator(withIssuer, audienceValidator)

    jwtDecoder.setJwtValidator(withAudience)

    return jwtDecoder
}</code></pre>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="oauth2resourceserver-jwt-claimsetmapping"><a class="anchor" href="oauth2-resourceserver.html#oauth2resourceserver-jwt-claimsetmapping"></a>Configuring Claim Set Mapping</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Spring Security uses the <a href="https://bitbucket.org/connect2id/nimbus-jose-jwt/wiki/Home">Nimbus</a> library for parsing JWTs and validating their signatures.
Consequently, Spring Security is subject to Nimbus&#8217;s interpretation of each field value and how to coerce each into a Java type.</p>
</div>
<div class="paragraph">
<p>For example, because Nimbus remains Java 7 compatible, it doesn&#8217;t use <code>Instant</code> to represent timestamp fields.</p>
</div>
<div class="paragraph">
<p>And it&#8217;s entirely possible to use a different library or for JWT processing, which may make its own coercion decisions that need adjustment.</p>
</div>
<div class="paragraph">
<p>Or, quite simply, a resource server may want to add or remove claims from a JWT for domain-specific reasons.</p>
</div>
<div class="paragraph">
<p>For these purposes, Resource Server supports mapping the JWT claim set with <code>MappedJwtClaimSetConverter</code>.</p>
</div>
<div class="sect2">
<h3 id="oauth2resourceserver-jwt-claimsetmapping-singleclaim"><a class="anchor" href="oauth2-resourceserver.html#oauth2resourceserver-jwt-claimsetmapping-singleclaim"></a>Customizing the Conversion of a Single Claim</h3>
<div class="paragraph">
<p>By default, <code>MappedJwtClaimSetConverter</code> will attempt to coerce claims into the following types:</p>
</div>
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 50%;">
<col style="width: 50%;">
</colgroup>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Claim</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Java Type</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>aud</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>Collection&lt;String&gt;</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>exp</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>Instant</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>iat</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>Instant</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>iss</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>String</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>jti</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>String</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>nbf</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>Instant</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>sub</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>String</code></p></td>
</tr>
</tbody>
</table>
<div class="paragraph">
<p>An individual claim&#8217;s conversion strategy can be configured using <code>MappedJwtClaimSetConverter.withDefaults</code>:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Bean
JwtDecoder jwtDecoder() {
    NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withJwkSetUri(jwkSetUri).build();

    MappedJwtClaimSetConverter converter = MappedJwtClaimSetConverter
            .withDefaults(Collections.singletonMap("sub", this::lookupUserIdBySub));
    jwtDecoder.setClaimSetConverter(converter);

    return jwtDecoder;
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">@Bean
fun jwtDecoder(): JwtDecoder {
    val jwtDecoder = NimbusJwtDecoder.withJwkSetUri(jwkSetUri).build()

    val converter = MappedJwtClaimSetConverter
            .withDefaults(mapOf("sub" to this::lookupUserIdBySub))
    jwtDecoder.setClaimSetConverter(converter)

    return jwtDecoder
}</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>This will keep all the defaults, except it will override the default claim converter for <code>sub</code>.</p>
</div>
</div>
<div class="sect2">
<h3 id="oauth2resourceserver-jwt-claimsetmapping-add"><a class="anchor" href="oauth2-resourceserver.html#oauth2resourceserver-jwt-claimsetmapping-add"></a>Adding a Claim</h3>
<div class="paragraph">
<p><code>MappedJwtClaimSetConverter</code> can also be used to add a custom claim, for example, to adapt to an existing system:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">MappedJwtClaimSetConverter.withDefaults(Collections.singletonMap("custom", custom -&gt; "value"));</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">MappedJwtClaimSetConverter.withDefaults(mapOf("custom" to Converter&lt;Any, String&gt; { "value" }))</code></pre>
</div>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="oauth2resourceserver-jwt-claimsetmapping-remove"><a class="anchor" href="oauth2-resourceserver.html#oauth2resourceserver-jwt-claimsetmapping-remove"></a>Removing a Claim</h3>
<div class="paragraph">
<p>And removing a claim is also simple, using the same API:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">MappedJwtClaimSetConverter.withDefaults(Collections.singletonMap("legacyclaim", legacy -&gt; null));</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">MappedJwtClaimSetConverter.withDefaults(mapOf("legacyclaim" to Converter&lt;Any, Any&gt; { null }))</code></pre>
</div>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="oauth2resourceserver-jwt-claimsetmapping-rename"><a class="anchor" href="oauth2-resourceserver.html#oauth2resourceserver-jwt-claimsetmapping-rename"></a>Renaming a Claim</h3>
<div class="paragraph">
<p>In more sophisticated scenarios, like consulting multiple claims at once or renaming a claim, Resource Server accepts any class that implements <code>Converter&lt;Map&lt;String, Object&gt;, Map&lt;String,Object&gt;&gt;</code>:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">public class UsernameSubClaimAdapter implements Converter&lt;Map&lt;String, Object&gt;, Map&lt;String, Object&gt;&gt; {
    private final MappedJwtClaimSetConverter delegate =
            MappedJwtClaimSetConverter.withDefaults(Collections.emptyMap());

    public Map&lt;String, Object&gt; convert(Map&lt;String, Object&gt; claims) {
        Map&lt;String, Object&gt; convertedClaims = this.delegate.convert(claims);

        String username = (String) convertedClaims.get("user_name");
        convertedClaims.put("sub", username);

        return convertedClaims;
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">class UsernameSubClaimAdapter : Converter&lt;Map&lt;String, Any?&gt;, Map&lt;String, Any?&gt;&gt; {
    private val delegate = MappedJwtClaimSetConverter.withDefaults(Collections.emptyMap())
    override fun convert(claims: Map&lt;String, Any?&gt;): Map&lt;String, Any?&gt; {
        val convertedClaims = delegate.convert(claims)
        val username = convertedClaims["user_name"] as String
        convertedClaims["sub"] = username
        return convertedClaims
    }
}</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>And then, the instance can be supplied like normal:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Bean
JwtDecoder jwtDecoder() {
    NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withJwkSetUri(jwkSetUri).build();
    jwtDecoder.setClaimSetConverter(new UsernameSubClaimAdapter());
    return jwtDecoder;
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">@Bean
fun jwtDecoder(): JwtDecoder {
    val jwtDecoder: NimbusJwtDecoder = NimbusJwtDecoder.withJwkSetUri(jwkSetUri).build()
    jwtDecoder.setClaimSetConverter(UsernameSubClaimAdapter())
    return jwtDecoder
}</code></pre>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="oauth2resourceserver-jwt-timeouts"><a class="anchor" href="oauth2-resourceserver.html#oauth2resourceserver-jwt-timeouts"></a>Configuring Timeouts</h2>
<div class="sectionbody">
<div class="paragraph">
<p>By default, Resource Server uses connection and socket timeouts of 30 seconds each for coordinating with the authorization server.</p>
</div>
<div class="paragraph">
<p>This may be too short in some scenarios.
Further, it doesn&#8217;t take into account more sophisticated patterns like back-off and discovery.</p>
</div>
<div class="paragraph">
<p>To adjust the way in which Resource Server connects to the authorization server, <code>NimbusJwtDecoder</code> accepts an instance of <code>RestOperations</code>:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Bean
public JwtDecoder jwtDecoder(RestTemplateBuilder builder) {
    RestOperations rest = builder
            .setConnectTimeout(Duration.ofSeconds(60))
            .setReadTimeout(Duration.ofSeconds(60))
            .build();

    NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withJwkSetUri(jwkSetUri).restOperations(rest).build();
    return jwtDecoder;
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">@Bean
fun jwtDecoder(builder: RestTemplateBuilder): JwtDecoder {
    val rest: RestOperations = builder
            .setConnectTimeout(Duration.ofSeconds(60))
            .setReadTimeout(Duration.ofSeconds(60))
            .build()
    return NimbusJwtDecoder.withJwkSetUri(jwkSetUri).restOperations(rest).build()
}</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>Also by default, Resource Server caches in-memory the authorization server&#8217;s JWK set for 5 minutes, which you may want to adjust.
Further, it doesn&#8217;t take into account more sophisticated caching patterns like eviction or using a shared cache.</p>
</div>
<div class="paragraph">
<p>To adjust the way in which Resource Server caches the JWK set, <code>NimbusJwtDecoder</code> accepts an instance of <code>Cache</code>:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Bean
public JwtDecoder jwtDecoder(CacheManager cacheManager) {
    return NimbusJwtDecoder.withJwkSetUri(jwkSetUri)
            .cache(cacheManager.getCache("jwks"))
            .build();
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">@Bean
fun jwtDecoder(cacheManager: CacheManager): JwtDecoder {
    return NimbusJwtDecoder.withJwkSetUri(jwkSetUri)
            .cache(cacheManager.getCache("jwks"))
            .build()
}</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>When given a <code>Cache</code>, Resource Server will use the JWK Set Uri as the key and the JWK Set JSON as the value.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
Spring isn&#8217;t a cache provider, so you&#8217;ll need to make sure to include the appropriate dependencies, like <code>spring-boot-starter-cache</code> and your favorite caching provider.
</td>
</tr>
</table>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
Whether it&#8217;s socket or cache timeouts, you may instead want to work with Nimbus directly.
To do so, remember that <code>NimbusJwtDecoder</code> ships with a constructor that takes Nimbus&#8217;s <code>JWTProcessor</code>.
</td>
</tr>
</table>
</div>
</div>
</div>
<div class="sect1">
<h2 id="oauth2resourceserver-opaque-minimaldependencies"><a class="anchor" href="oauth2-resourceserver.html#oauth2resourceserver-opaque-minimaldependencies"></a>Minimal Dependencies for Introspection</h2>
<div class="sectionbody">
<div class="paragraph">
<p>As described in <a href="oauth2-resourceserver.html#oauth2resourceserver-jwt-minimaldependencies">Minimal Dependencies for JWT</a> most of Resource Server support is collected in <code>spring-security-oauth2-resource-server</code>.
However unless a custom <a href="oauth2-resourceserver.html#oauth2resourceserver-opaque-introspector"><code>OpaqueTokenIntrospector</code></a> is provided, the Resource Server will fallback to NimbusOpaqueTokenIntrospector.
Meaning that both <code>spring-security-oauth2-resource-server</code> and <code>oauth2-oidc-sdk</code> are necessary in order to have a working minimal Resource Server that supports opaque Bearer Tokens.
Please refer to <code>spring-security-oauth2-resource-server</code> in order to determin the correct version for <code>oauth2-oidc-sdk</code>.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="oauth2resourceserver-opaque-minimalconfiguration"><a class="anchor" href="oauth2-resourceserver.html#oauth2resourceserver-opaque-minimalconfiguration"></a>Minimal Configuration for Introspection</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Typically, an opaque token can be verified via an <a href="https://tools.ietf.org/html/rfc7662">OAuth 2.0 Introspection Endpoint</a>, hosted by the authorization server.
This can be handy when revocation is a requirement.</p>
</div>
<div class="paragraph">
<p>When using <a href="https://spring.io/projects/spring-boot">Spring Boot</a>, configuring an application as a resource server that uses introspection consists of two basic steps.
First, include the needed dependencies and second, indicate the introspection endpoint details.</p>
</div>
<div class="sect2">
<h3 id="oauth2resourceserver-opaque-introspectionuri"><a class="anchor" href="oauth2-resourceserver.html#oauth2resourceserver-opaque-introspectionuri"></a>Specifying the Authorization Server</h3>
<div class="paragraph">
<p>To specify where the introspection endpoint is, simply do:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-yaml hljs" data-lang="yaml">security:
  oauth2:
    resourceserver:
      opaque-token:
        introspection-uri: https://idp.example.com/introspect
        client-id: client
        client-secret: secret</code></pre>
</div>
</div>
<div class="paragraph">
<p>Where <code><a href="https://idp.example.com/introspect" class="bare">https://idp.example.com/introspect</a></code> is the introspection endpoint hosted by your authorization server and <code>client-id</code> and <code>client-secret</code> are the credentials needed to hit that endpoint.</p>
</div>
<div class="paragraph">
<p>Resource Server will use these properties to further self-configure and subsequently validate incoming JWTs.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
When using introspection, the authorization server&#8217;s word is the law.
If the authorization server responses that the token is valid, then it is.
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>And that&#8217;s it!</p>
</div>
</div>
<div class="sect2">
<h3 id="_startup_expectations_2"><a class="anchor" href="oauth2-resourceserver.html#_startup_expectations_2"></a>Startup Expectations</h3>
<div class="paragraph">
<p>When this property and these dependencies are used, Resource Server will automatically configure itself to validate Opaque Bearer Tokens.</p>
</div>
<div class="paragraph">
<p>This startup process is quite a bit simpler than for JWTs since no endpoints need to be discovered and no additional validation rules get added.</p>
</div>
</div>
<div class="sect2">
<h3 id="_runtime_expectations_2"><a class="anchor" href="oauth2-resourceserver.html#_runtime_expectations_2"></a>Runtime Expectations</h3>
<div class="paragraph">
<p>Once the application is started up, Resource Server will attempt to process any request containing an <code>Authorization: Bearer</code> header:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-http hljs" data-lang="http">GET / HTTP/1.1
Authorization: Bearer some-token-value # Resource Server will process this</code></pre>
</div>
</div>
<div class="paragraph">
<p>So long as this scheme is indicated, Resource Server will attempt to process the request according to the Bearer Token specification.</p>
</div>
<div class="paragraph">
<p>Given an Opaque Token, Resource Server will</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>Query the provided introspection endpoint using the provided credentials and the token</p>
</li>
<li>
<p>Inspect the response for an <code>{ 'active' : true }</code> attribute</p>
</li>
<li>
<p>Map each scope to an authority with the prefix <code>SCOPE_</code></p>
</li>
</ol>
</div>
<div class="paragraph">
<p>The resulting <code>Authentication#getPrincipal</code>, by default, is a Spring Security <code><a href="https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/oauth2/core/OAuth2AuthenticatedPrincipal.html">OAuth2AuthenticatedPrincipal</a></code> object, and <code>Authentication#getName</code> maps to the token&#8217;s <code>sub</code> property, if one is present.</p>
</div>
<div class="paragraph">
<p>From here, you may want to jump to:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="oauth2-resourceserver.html#oauth2resourceserver-opaque-architecture">How Opaque Token Authentication Works</a></p>
</li>
<li>
<p><a href="oauth2-resourceserver.html#oauth2resourceserver-opaque-attributes">Looking Up Attributes Post-Authentication</a></p>
</li>
<li>
<p><a href="oauth2-resourceserver.html#oauth2resourceserver-opaque-authorization-extraction">Extracting Authorities Manually</a></p>
</li>
<li>
<p><a href="oauth2-resourceserver.html#oauth2resourceserver-opaque-jwt-introspector">Using Introspection with JWTs</a></p>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="oauth2resourceserver-opaque-architecture"><a class="anchor" href="oauth2-resourceserver.html#oauth2resourceserver-opaque-architecture"></a>How Opaque Token Authentication Works</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Next, let&#8217;s see the architectural components that Spring Security uses to support <a href="https://tools.ietf.org/html/rfc7662">opaque token</a> Authentication in servlet-based applications, like the one we just saw.</p>
</div>
<div class="paragraph">
<p><a href="https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/oauth2/server/resource/authentication/OpaqueTokenAuthenticationProvider.html"><code>OpaqueTokenAuthenticationProvider</code></a> is an <a href="../authentication/architecture.html#servlet-authentication-authenticationprovider" class="xref page"><code>AuthenticationProvider</code></a> implementation that leverages a <a href="oauth2-resourceserver.html#oauth2resourceserver-opaque-introspector"><code>OpaqueTokenIntrospector</code></a> to authenticate an opaque token.</p>
</div>
<div class="paragraph">
<p>Let&#8217;s take a look at how <code>OpaqueTokenAuthenticationProvider</code> works within Spring Security.
The figure explains details of how the <a href="../authentication/architecture.html#servlet-authentication-authenticationmanager" class="xref page"><code>AuthenticationManager</code></a> in figures from <a href="oauth2-resourceserver.html#oauth2resourceserver-authentication-bearertokenauthenticationfilter">Reading the Bearer Token</a> works.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="../../_images/servlet/oauth2/opaquetokenauthenticationprovider.png" alt="opaquetokenauthenticationprovider">
</div>
<div class="title">Figure 4. <code>OpaqueTokenAuthenticationProvider</code> Usage</div>
</div>
<div class="paragraph">
<p><span class="image"><img src="../../_images/icons/number_1.png" alt="number 1"></span> The authentication <code>Filter</code> from <a href="oauth2-resourceserver.html#oauth2resourceserver-authentication-bearertokenauthenticationfilter">Reading the Bearer Token</a> passes a <code>BearerTokenAuthenticationToken</code> to the <code>AuthenticationManager</code> which is implemented by <a href="../authentication/architecture.html#servlet-authentication-providermanager" class="xref page"><code>ProviderManager</code></a>.</p>
</div>
<div class="paragraph">
<p><span class="image"><img src="../../_images/icons/number_2.png" alt="number 2"></span> The <code>ProviderManager</code> is configured to use an <a href="../authentication/architecture.html#servlet-authentication-authenticationprovider" class="xref page">AuthenticationProvider</a> of type <code>OpaqueTokenAuthenticationProvider</code>.</p>
</div>
<div id="oauth2resourceserver-opaque-architecture-introspector" class="paragraph">
<p><span class="image"><img src="../../_images/icons/number_3.png" alt="number 3"></span> <code>OpaqueTokenAuthenticationProvider</code> introspects the opaque token and adds granted authorities using an <a href="oauth2-resourceserver.html#oauth2resourceserver-opaque-introspector"><code>OpaqueTokenIntrospector</code></a>.
When authentication is successful, the <a href="../authentication/architecture.html#servlet-authentication-authentication" class="xref page"><code>Authentication</code></a> that is returned is of type <code>BearerTokenAuthentication</code> and has a principal that is the <code>OAuth2AuthenticatedPrincipal</code> returned by the configured <a href="oauth2-resourceserver.html#oauth2resourceserver-opaque-introspector"><code>OpaqueTokenIntrospector</code></a>.
Ultimately, the returned <code>BearerTokenAuthentication</code> will be set on the <a href="../authentication/architecture.html#servlet-authentication-securitycontextholder" class="xref page"><code>SecurityContextHolder</code></a> by the authentication <code>Filter</code>.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="oauth2resourceserver-opaque-attributes"><a class="anchor" href="oauth2-resourceserver.html#oauth2resourceserver-opaque-attributes"></a>Looking Up Attributes Post-Authentication</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Once a token is authenticated, an instance of <code>BearerTokenAuthentication</code> is set in the <code>SecurityContext</code>.</p>
</div>
<div class="paragraph">
<p>This means that it&#8217;s available in <code>@Controller</code> methods when using <code>@EnableWebMvc</code> in your configuration:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@GetMapping("/foo")
public String foo(BearerTokenAuthentication authentication) {
    return authentication.getTokenAttributes().get("sub") + " is the subject";
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">@GetMapping("/foo")
fun foo(authentication: BearerTokenAuthentication): String {
    return authentication.tokenAttributes["sub"].toString() + " is the subject"
}</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>Since <code>BearerTokenAuthentication</code> holds an <code>OAuth2AuthenticatedPrincipal</code>, that also means that it&#8217;s available to controller methods, too:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@GetMapping("/foo")
public String foo(@AuthenticationPrincipal OAuth2AuthenticatedPrincipal principal) {
    return principal.getAttribute("sub") + " is the subject";
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">@GetMapping("/foo")
fun foo(@AuthenticationPrincipal principal: OAuth2AuthenticatedPrincipal): String {
    return principal.getAttribute&lt;Any&gt;("sub").toString() + " is the subject"
}</code></pre>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_looking_up_attributes_via_spel"><a class="anchor" href="oauth2-resourceserver.html#_looking_up_attributes_via_spel"></a>Looking Up Attributes Via SpEL</h3>
<div class="paragraph">
<p>Of course, this also means that attributes can be accessed via SpEL.</p>
</div>
<div class="paragraph">
<p>For example, if using <code>@EnableGlobalMethodSecurity</code> so that you can use <code>@PreAuthorize</code> annotations, you can do:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@PreAuthorize("principal?.attributes['sub'] == 'foo'")
public String forFoosEyesOnly() {
    return "foo";
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">@PreAuthorize("principal?.attributes['sub'] == 'foo'")
fun forFoosEyesOnly(): String {
    return "foo"
}</code></pre>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="oauth2resourceserver-opaque-sansboot"><a class="anchor" href="oauth2-resourceserver.html#oauth2resourceserver-opaque-sansboot"></a>Overriding or Replacing Boot Auto Configuration</h2>
<div class="sectionbody">
<div class="paragraph">
<p>There are two <code>@Bean</code>s that Spring Boot generates on Resource Server&#8217;s behalf.</p>
</div>
<div class="paragraph">
<p>The first is a <code>WebSecurityConfigurerAdapter</code> that configures the app as a resource server.
When use Opaque Token, this <code>WebSecurityConfigurerAdapter</code> looks like:</p>
</div>
<div class="exampleblock">
<div class="title">Example 11. Default Opaque Token Configuration</div>
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">protected void configure(HttpSecurity http) {
    http
        .authorizeRequests(authorize -&gt; authorize
            .anyRequest().authenticated()
        )
        .oauth2ResourceServer(OAuth2ResourceServerConfigurer::opaqueToken);
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">override fun configure(http: HttpSecurity) {
    http {
        authorizeRequests {
            authorize(anyRequest, authenticated)
        }
        oauth2ResourceServer {
            opaqueToken { }
        }
    }
}</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>If the application doesn&#8217;t expose a <code>WebSecurityConfigurerAdapter</code> bean, then Spring Boot will expose the above default one.</p>
</div>
<div class="paragraph">
<p>Replacing this is as simple as exposing the bean within the application:</p>
</div>
<div class="exampleblock">
<div class="title">Example 12. Custom Opaque Token Configuration</div>
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@EnableWebSecurity
public class MyCustomSecurityConfiguration extends WebSecurityConfigurerAdapter {
    protected void configure(HttpSecurity http) {
        http
            .authorizeRequests(authorize -&gt; authorize
                .mvcMatchers("/messages/**").hasAuthority("SCOPE_message:read")
                .anyRequest().authenticated()
            )
            .oauth2ResourceServer(oauth2 -&gt; oauth2
                .opaqueToken(opaqueToken -&gt; opaqueToken
                    .introspector(myIntrospector())
                )
            );
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">@EnableWebSecurity
class MyCustomSecurityConfiguration : WebSecurityConfigurerAdapter() {
    override fun configure(http: HttpSecurity) {
        http {
            authorizeRequests {
                authorize("/messages/**", hasAuthority("SCOPE_message:read"))
                authorize(anyRequest, authenticated)
            }
            oauth2ResourceServer {
                opaqueToken {
                    introspector = myIntrospector()
                }
            }
        }
    }
}</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>The above requires the scope of <code>message:read</code> for any URL that starts with <code>/messages/</code>.</p>
</div>
<div class="paragraph">
<p>Methods on the <code>oauth2ResourceServer</code> DSL will also override or replace auto configuration.</p>
</div>
<div id="oauth2resourceserver-opaque-introspector" class="paragraph">
<p>For example, the second <code>@Bean</code> Spring Boot creates is an <code>OpaqueTokenIntrospector</code>, <a href="oauth2-resourceserver.html#oauth2resourceserver-opaque-architecture-introspector">which decodes <code>String</code> tokens into validated instances of <code>OAuth2AuthenticatedPrincipal</code></a>:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Bean
public OpaqueTokenIntrospector introspector() {
    return new NimbusOpaqueTokenIntrospector(introspectionUri, clientId, clientSecret);
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">@Bean
fun introspector(): OpaqueTokenIntrospector {
    return NimbusOpaqueTokenIntrospector(introspectionUri, clientId, clientSecret)
}</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>If the application doesn&#8217;t expose a <a href="oauth2-resourceserver.html#oauth2resourceserver-opaque-architecture-introspector"><code>OpaqueTokenIntrospector</code></a> bean, then Spring Boot will expose the above default one.</p>
</div>
<div class="paragraph">
<p>And its configuration can be overridden using <code>introspectionUri()</code> and <code>introspectionClientCredentials()</code> or replaced using <code>introspector()</code>.</p>
</div>
<div class="paragraph">
<p>Or, if you&#8217;re not using Spring Boot at all, then both of these components - the filter chain and a <a href="oauth2-resourceserver.html#oauth2resourceserver-opaque-architecture-introspector"><code>OpaqueTokenIntrospector</code></a> can be specified in XML.</p>
</div>
<div class="paragraph">
<p>The filter chain is specified like so:</p>
</div>
<div class="exampleblock">
<div class="title">Example 13. Default Opaque Token Configuration</div>
<div class="content">
<div class="listingblock primary">
<div class="title">Xml</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml">&lt;http&gt;
    &lt;intercept-uri pattern="/**" access="authenticated"/&gt;
    &lt;oauth2-resource-server&gt;
        &lt;opaque-token introspector-ref="opaqueTokenIntrospector"/&gt;
    &lt;/oauth2-resource-server&gt;
&lt;/http&gt;</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>And the <a href="oauth2-resourceserver.html#oauth2resourceserver-opaque-architecture-introspector"><code>OpaqueTokenIntrospector</code></a> like so:</p>
</div>
<div class="exampleblock">
<div class="title">Example 14. Opaque Token Introspector</div>
<div class="content">
<div class="listingblock primary">
<div class="title">Xml</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml">&lt;bean id="opaqueTokenIntrospector"
        class="org.springframework.security.oauth2.server.resource.introspection.NimbusOpaqueTokenIntrospector"&gt;
    &lt;constructor-arg value="${spring.security.oauth2.resourceserver.opaquetoken.introspection_uri}"/&gt;
    &lt;constructor-arg value="${spring.security.oauth2.resourceserver.opaquetoken.client_id}"/&gt;
    &lt;constructor-arg value="${spring.security.oauth2.resourceserver.opaquetoken.client_secret}"/&gt;
&lt;/bean&gt;</code></pre>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="oauth2resourceserver-opaque-introspectionuri-dsl"><a class="anchor" href="oauth2-resourceserver.html#oauth2resourceserver-opaque-introspectionuri-dsl"></a>Using <code>introspectionUri()</code></h3>
<div class="paragraph">
<p>An authorization server&#8217;s Introspection Uri can be configured <a href="oauth2-resourceserver.html#oauth2resourceserver-opaque-introspectionuri">as a configuration property</a> or it can be supplied in the DSL:</p>
</div>
<div class="exampleblock">
<div class="title">Example 15. Introspection URI Configuration</div>
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@EnableWebSecurity
public class DirectlyConfiguredIntrospectionUri extends WebSecurityConfigurerAdapter {
    protected void configure(HttpSecurity http) {
        http
            .authorizeRequests(authorize -&gt; authorize
                .anyRequest().authenticated()
            )
            .oauth2ResourceServer(oauth2 -&gt; oauth2
                .opaqueToken(opaqueToken -&gt; opaqueToken
                    .introspectionUri("https://idp.example.com/introspect")
                    .introspectionClientCredentials("client", "secret")
                )
            );
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">@EnableWebSecurity
class DirectlyConfiguredIntrospectionUri : WebSecurityConfigurerAdapter() {
    override fun configure(http: HttpSecurity) {
        http {
            authorizeRequests {
                authorize(anyRequest, authenticated)
            }
            oauth2ResourceServer {
                opaqueToken {
                    introspectionUri = "https://idp.example.com/introspect"
                    introspectionClientCredentials("client", "secret")
                }
            }
        }
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Xml</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml">&lt;bean id="opaqueTokenIntrospector"
        class="org.springframework.security.oauth2.server.resource.introspection.NimbusOpaqueTokenIntrospector"&gt;
    &lt;constructor-arg value="https://idp.example.com/introspect"/&gt;
    &lt;constructor-arg value="client"/&gt;
    &lt;constructor-arg value="secret"/&gt;
&lt;/bean&gt;</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>Using <code>introspectionUri()</code> takes precedence over any configuration property.</p>
</div>
</div>
<div class="sect2">
<h3 id="oauth2resourceserver-opaque-introspector-dsl"><a class="anchor" href="oauth2-resourceserver.html#oauth2resourceserver-opaque-introspector-dsl"></a>Using <code>introspector()</code></h3>
<div class="paragraph">
<p>More powerful than <code>introspectionUri()</code> is <code>introspector()</code>, which will completely replace any Boot auto configuration of <a href="oauth2-resourceserver.html#oauth2resourceserver-opaque-architecture-introspector"><code>OpaqueTokenIntrospector</code></a>:</p>
</div>
<div class="exampleblock">
<div class="title">Example 16. Introspector Configuration</div>
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@EnableWebSecurity
public class DirectlyConfiguredIntrospector extends WebSecurityConfigurerAdapter {
    protected void configure(HttpSecurity http) {
        http
            .authorizeRequests(authorize -&gt; authorize
                .anyRequest().authenticated()
            )
            .oauth2ResourceServer(oauth2 -&gt; oauth2
                .opaqueToken(opaqueToken -&gt; opaqueToken
                    .introspector(myCustomIntrospector())
                )
            );
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">@EnableWebSecurity
class DirectlyConfiguredIntrospector : WebSecurityConfigurerAdapter() {
    override fun configure(http: HttpSecurity) {
        http {
            authorizeRequests {
                authorize(anyRequest, authenticated)
            }
            oauth2ResourceServer {
                opaqueToken {
                    introspector = myCustomIntrospector()
                }
            }
        }
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Xml</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml">&lt;http&gt;
    &lt;intercept-uri pattern="/**" access="authenticated"/&gt;
    &lt;oauth2-resource-server&gt;
        &lt;opaque-token introspector-ref="myCustomIntrospector"/&gt;
    &lt;/oauth2-resource-server&gt;
&lt;/http&gt;</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>This is handy when deeper configuration, like <a href="oauth2-resourceserver.html#oauth2resourceserver-opaque-authorization-extraction">authority mapping</a>, <a href="oauth2-resourceserver.html#oauth2resourceserver-opaque-jwt-introspector">JWT revocation</a>, or <a href="oauth2-resourceserver.html#oauth2resourceserver-opaque-timeouts">request timeouts</a>, is necessary.</p>
</div>
</div>
<div class="sect2">
<h3 id="oauth2resourceserver-opaque-introspector-bean"><a class="anchor" href="oauth2-resourceserver.html#oauth2resourceserver-opaque-introspector-bean"></a>Exposing a <code>OpaqueTokenIntrospector</code> <code>@Bean</code></h3>
<div class="paragraph">
<p>Or, exposing a <a href="oauth2-resourceserver.html#oauth2resourceserver-opaque-architecture-introspector"><code>OpaqueTokenIntrospector</code></a> <code>@Bean</code> has the same effect as <code>introspector()</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Bean
public OpaqueTokenIntrospector introspector() {
    return new NimbusOpaqueTokenIntrospector(introspectionUri, clientId, clientSecret);
}</code></pre>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="oauth2resourceserver-opaque-authorization"><a class="anchor" href="oauth2-resourceserver.html#oauth2resourceserver-opaque-authorization"></a>Configuring Authorization</h2>
<div class="sectionbody">
<div class="paragraph">
<p>An OAuth 2.0 Introspection endpoint will typically return a <code>scope</code> attribute, indicating the scopes (or authorities) it&#8217;s been granted, for example:</p>
</div>
<div class="paragraph">
<p><code>{ &#8230;&#8203;, "scope" : "messages contacts"}</code></p>
</div>
<div class="paragraph">
<p>When this is the case, Resource Server will attempt to coerce these scopes into a list of granted authorities, prefixing each scope with the string "SCOPE_".</p>
</div>
<div class="paragraph">
<p>This means that to protect an endpoint or method with a scope derived from an Opaque Token, the corresponding expressions should include this prefix:</p>
</div>
<div class="exampleblock">
<div class="title">Example 17. Authorization Opaque Token Configuration</div>
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@EnableWebSecurity
public class MappedAuthorities extends WebSecurityConfigurerAdapter {
    protected void configure(HttpSecurity http) {
        http
            .authorizeRequests(authorizeRequests -&gt; authorizeRequests
                .mvcMatchers("/contacts/**").hasAuthority("SCOPE_contacts")
                .mvcMatchers("/messages/**").hasAuthority("SCOPE_messages")
                .anyRequest().authenticated()
            )
            .oauth2ResourceServer(OAuth2ResourceServerConfigurer::opaqueToken);
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">@EnableWebSecurity
class MappedAuthorities : WebSecurityConfigurerAdapter() {
    override fun configure(http: HttpSecurity) {
       http {
            authorizeRequests {
                authorize("/contacts/**", hasAuthority("SCOPE_contacts"))
                authorize("/messages/**", hasAuthority("SCOPE_messages"))
                authorize(anyRequest, authenticated)
            }
           oauth2ResourceServer {
               opaqueToken { }
           }
        }
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Xml</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml">&lt;http&gt;
    &lt;intercept-uri pattern="/contacts/**" access="hasAuthority('SCOPE_contacts')"/&gt;
    &lt;intercept-uri pattern="/messages/**" access="hasAuthority('SCOPE_messages')"/&gt;
    &lt;oauth2-resource-server&gt;
        &lt;opaque-token introspector-ref="opaqueTokenIntrospector"/&gt;
    &lt;/oauth2-resource-server&gt;
&lt;/http&gt;</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>Or similarly with method security:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@PreAuthorize("hasAuthority('SCOPE_messages')")
public List&lt;Message&gt; getMessages(...) {}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">@PreAuthorize("hasAuthority('SCOPE_messages')")
fun getMessages(): List&lt;Message?&gt; {}</code></pre>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="oauth2resourceserver-opaque-authorization-extraction"><a class="anchor" href="oauth2-resourceserver.html#oauth2resourceserver-opaque-authorization-extraction"></a>Extracting Authorities Manually</h3>
<div class="paragraph">
<p>By default, Opaque Token support will extract the scope claim from an introspection response and parse it into individual <code>GrantedAuthority</code> instances.</p>
</div>
<div class="paragraph">
<p>For example, if the introspection response were:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-json hljs" data-lang="json">{
    "active" : true,
    "scope" : "message:read message:write"
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Then Resource Server would generate an <code>Authentication</code> with two authorities, one for <code>message:read</code> and the other for <code>message:write</code>.</p>
</div>
<div class="paragraph">
<p>This can, of course, be customized using a custom <a href="oauth2-resourceserver.html#oauth2resourceserver-opaque-architecture-introspector"><code>OpaqueTokenIntrospector</code></a> that takes a look at the attribute set and converts in its own way:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">public class CustomAuthoritiesOpaqueTokenIntrospector implements OpaqueTokenIntrospector {
    private OpaqueTokenIntrospector delegate =
            new NimbusOpaqueTokenIntrospector("https://idp.example.org/introspect", "client", "secret");

    public OAuth2AuthenticatedPrincipal introspect(String token) {
        OAuth2AuthenticatedPrincipal principal = this.delegate.introspect(token);
        return new DefaultOAuth2AuthenticatedPrincipal(
                principal.getName(), principal.getAttributes(), extractAuthorities(principal));
    }

    private Collection&lt;GrantedAuthority&gt; extractAuthorities(OAuth2AuthenticatedPrincipal principal) {
        List&lt;String&gt; scopes = principal.getAttribute(OAuth2IntrospectionClaimNames.SCOPE);
        return scopes.stream()
                .map(SimpleGrantedAuthority::new)
                .collect(Collectors.toList());
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">class CustomAuthoritiesOpaqueTokenIntrospector : OpaqueTokenIntrospector {
    private val delegate: OpaqueTokenIntrospector = NimbusOpaqueTokenIntrospector("https://idp.example.org/introspect", "client", "secret")
    override fun introspect(token: String): OAuth2AuthenticatedPrincipal {
        val principal: OAuth2AuthenticatedPrincipal = delegate.introspect(token)
        return DefaultOAuth2AuthenticatedPrincipal(
                principal.name, principal.attributes, extractAuthorities(principal))
    }

    private fun extractAuthorities(principal: OAuth2AuthenticatedPrincipal): Collection&lt;GrantedAuthority&gt; {
        val scopes: List&lt;String&gt; = principal.getAttribute(OAuth2IntrospectionClaimNames.SCOPE)
        return scopes
                .map { SimpleGrantedAuthority(it) }
    }
}</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>Thereafter, this custom introspector can be configured simply by exposing it as a <code>@Bean</code>:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Bean
public OpaqueTokenIntrospector introspector() {
    return new CustomAuthoritiesOpaqueTokenIntrospector();
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">@Bean
fun introspector(): OpaqueTokenIntrospector {
    return CustomAuthoritiesOpaqueTokenIntrospector()
}</code></pre>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="oauth2resourceserver-opaque-timeouts"><a class="anchor" href="oauth2-resourceserver.html#oauth2resourceserver-opaque-timeouts"></a>Configuring Timeouts</h2>
<div class="sectionbody">
<div class="paragraph">
<p>By default, Resource Server uses connection and socket timeouts of 30 seconds each for coordinating with the authorization server.</p>
</div>
<div class="paragraph">
<p>This may be too short in some scenarios.
Further, it doesn&#8217;t take into account more sophisticated patterns like back-off and discovery.</p>
</div>
<div class="paragraph">
<p>To adjust the way in which Resource Server connects to the authorization server, <code>NimbusOpaqueTokenIntrospector</code> accepts an instance of <code>RestOperations</code>:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Bean
public OpaqueTokenIntrospector introspector(RestTemplateBuilder builder, OAuth2ResourceServerProperties properties) {
    RestOperations rest = builder
            .basicAuthentication(properties.getOpaquetoken().getClientId(), properties.getOpaquetoken().getClientSecret())
            .setConnectTimeout(Duration.ofSeconds(60))
            .setReadTimeout(Duration.ofSeconds(60))
            .build();

    return new NimbusOpaqueTokenIntrospector(introspectionUri, rest);
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">@Bean
fun introspector(builder: RestTemplateBuilder, properties: OAuth2ResourceServerProperties): OpaqueTokenIntrospector? {
    val rest: RestOperations = builder
            .basicAuthentication(properties.opaquetoken.clientId, properties.opaquetoken.clientSecret)
            .setConnectTimeout(Duration.ofSeconds(60))
            .setReadTimeout(Duration.ofSeconds(60))
            .build()
    return NimbusOpaqueTokenIntrospector(introspectionUri, rest)
}</code></pre>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="oauth2resourceserver-opaque-jwt-introspector"><a class="anchor" href="oauth2-resourceserver.html#oauth2resourceserver-opaque-jwt-introspector"></a>Using Introspection with JWTs</h2>
<div class="sectionbody">
<div class="paragraph">
<p>A common question is whether or not introspection is compatible with JWTs.
Spring Security&#8217;s Opaque Token support has been designed to not care about the format of the token&#8201;&#8212;&#8201;it will gladly pass any token to the introspection endpoint provided.</p>
</div>
<div class="paragraph">
<p>So, let&#8217;s say that you&#8217;ve got a requirement that requires you to check with the authorization server on each request, in case the JWT has been revoked.</p>
</div>
<div class="paragraph">
<p>Even though you are using the JWT format for the token, your validation method is introspection, meaning you&#8217;d want to do:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-yaml hljs" data-lang="yaml">spring:
  security:
    oauth2:
      resourceserver:
        opaque-token:
          introspection-uri: https://idp.example.org/introspection
          client-id: client
          client-secret: secret</code></pre>
</div>
</div>
<div class="paragraph">
<p>In this case, the resulting <code>Authentication</code> would be <code>BearerTokenAuthentication</code>.
Any attributes in the corresponding <code>OAuth2AuthenticatedPrincipal</code> would be whatever was returned by the introspection endpoint.</p>
</div>
<div class="paragraph">
<p>But, let&#8217;s say that, oddly enough, the introspection endpoint only returns whether or not the token is active.
Now what?</p>
</div>
<div class="paragraph">
<p>In this case, you can create a custom <a href="oauth2-resourceserver.html#oauth2resourceserver-opaque-architecture-introspector"><code>OpaqueTokenIntrospector</code></a> that still hits the endpoint, but then updates the returned principal to have the JWTs claims as the attributes:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">public class JwtOpaqueTokenIntrospector implements OpaqueTokenIntrospector {
    private OpaqueTokenIntrospector delegate =
            new NimbusOpaqueTokenIntrospector("https://idp.example.org/introspect", "client", "secret");
    private JwtDecoder jwtDecoder = new NimbusJwtDecoder(new ParseOnlyJWTProcessor());

    public OAuth2AuthenticatedPrincipal introspect(String token) {
        OAuth2AuthenticatedPrincipal principal = this.delegate.introspect(token);
        try {
            Jwt jwt = this.jwtDecoder.decode(token);
            return new DefaultOAuth2AuthenticatedPrincipal(jwt.getClaims(), NO_AUTHORITIES);
        } catch (JwtException ex) {
            throw new OAuth2IntrospectionException(ex);
        }
    }

    private static class ParseOnlyJWTProcessor extends DefaultJWTProcessor&lt;SecurityContext&gt; {
    	JWTClaimsSet process(SignedJWT jwt, SecurityContext context)
                throws JOSEException {
            return jwt.getJWTClaimsSet();
        }
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">class JwtOpaqueTokenIntrospector : OpaqueTokenIntrospector {
    private val delegate: OpaqueTokenIntrospector = NimbusOpaqueTokenIntrospector("https://idp.example.org/introspect", "client", "secret")
    private val jwtDecoder: JwtDecoder = NimbusJwtDecoder(ParseOnlyJWTProcessor())
    override fun introspect(token: String): OAuth2AuthenticatedPrincipal {
        val principal = delegate.introspect(token)
        return try {
            val jwt: Jwt = jwtDecoder.decode(token)
            DefaultOAuth2AuthenticatedPrincipal(jwt.claims, NO_AUTHORITIES)
        } catch (ex: JwtException) {
            throw OAuth2IntrospectionException(ex.message)
        }
    }

    private class ParseOnlyJWTProcessor : DefaultJWTProcessor&lt;SecurityContext&gt;() {
        override fun process(jwt: SignedJWT, context: SecurityContext): JWTClaimsSet {
            return jwt.jwtClaimsSet
        }
    }
}</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>Thereafter, this custom introspector can be configured simply by exposing it as a <code>@Bean</code>:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Bean
public OpaqueTokenIntrospector introspector() {
    return new JwtOpaqueTokenIntrospector();
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">@Bean
fun introspector(): OpaqueTokenIntrospector {
    return JwtOpaqueTokenIntrospector()
}</code></pre>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="oauth2resourceserver-opaque-userinfo"><a class="anchor" href="oauth2-resourceserver.html#oauth2resourceserver-opaque-userinfo"></a>Calling a <code>/userinfo</code> Endpoint</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Generally speaking, a Resource Server doesn&#8217;t care about the underlying user, but instead about the authorities that have been granted.</p>
</div>
<div class="paragraph">
<p>That said, at times it can be valuable to tie the authorization statement back to a user.</p>
</div>
<div class="paragraph">
<p>If an application is also using <code>spring-security-oauth2-client</code>, having set up the appropriate <code>ClientRegistrationRepository</code>, then this is quite simple with a custom <a href="oauth2-resourceserver.html#oauth2resourceserver-opaque-architecture-introspector"><code>OpaqueTokenIntrospector</code></a>.
This implementation below does three things:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Delegates to the introspection endpoint, to affirm the token&#8217;s validity</p>
</li>
<li>
<p>Looks up the appropriate client registration associated with the <code>/userinfo</code> endpoint</p>
</li>
<li>
<p>Invokes and returns the response from the <code>/userinfo</code> endpoint</p>
</li>
</ul>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">public class UserInfoOpaqueTokenIntrospector implements OpaqueTokenIntrospector {
    private final OpaqueTokenIntrospector delegate =
            new NimbusOpaqueTokenIntrospector("https://idp.example.org/introspect", "client", "secret");
    private final OAuth2UserService oauth2UserService = new DefaultOAuth2UserService();

    private final ClientRegistrationRepository repository;

    // ... constructor

    @Override
    public OAuth2AuthenticatedPrincipal introspect(String token) {
        OAuth2AuthenticatedPrincipal authorized = this.delegate.introspect(token);
        Instant issuedAt = authorized.getAttribute(ISSUED_AT);
        Instant expiresAt = authorized.getAttribute(EXPIRES_AT);
        ClientRegistration clientRegistration = this.repository.findByRegistrationId("registration-id");
        OAuth2AccessToken token = new OAuth2AccessToken(BEARER, token, issuedAt, expiresAt);
        OAuth2UserRequest oauth2UserRequest = new OAuth2UserRequest(clientRegistration, token);
        return this.oauth2UserService.loadUser(oauth2UserRequest);
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">class UserInfoOpaqueTokenIntrospector : OpaqueTokenIntrospector {
    private val delegate: OpaqueTokenIntrospector = NimbusOpaqueTokenIntrospector("https://idp.example.org/introspect", "client", "secret")
    private val oauth2UserService = DefaultOAuth2UserService()
    private val repository: ClientRegistrationRepository? = null

    // ... constructor

    override fun introspect(token: String): OAuth2AuthenticatedPrincipal {
        val authorized = delegate.introspect(token)
        val issuedAt: Instant? = authorized.getAttribute(ISSUED_AT)
        val expiresAt: Instant? = authorized.getAttribute(EXPIRES_AT)
        val clientRegistration: ClientRegistration = repository!!.findByRegistrationId("registration-id")
        val accessToken = OAuth2AccessToken(BEARER, token, issuedAt, expiresAt)
        val oauth2UserRequest = OAuth2UserRequest(clientRegistration, accessToken)
        return oauth2UserService.loadUser(oauth2UserRequest)
    }
}</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>If you aren&#8217;t using <code>spring-security-oauth2-client</code>, it&#8217;s still quite simple.
You will simply need to invoke the <code>/userinfo</code> with your own instance of <code>WebClient</code>:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">public class UserInfoOpaqueTokenIntrospector implements OpaqueTokenIntrospector {
    private final OpaqueTokenIntrospector delegate =
            new NimbusOpaqueTokenIntrospector("https://idp.example.org/introspect", "client", "secret");
    private final WebClient rest = WebClient.create();

    @Override
    public OAuth2AuthenticatedPrincipal introspect(String token) {
        OAuth2AuthenticatedPrincipal authorized = this.delegate.introspect(token);
        return makeUserInfoRequest(authorized);
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">class UserInfoOpaqueTokenIntrospector : OpaqueTokenIntrospector {
    private val delegate: OpaqueTokenIntrospector = NimbusOpaqueTokenIntrospector("https://idp.example.org/introspect", "client", "secret")
    private val rest: WebClient = WebClient.create()

    override fun introspect(token: String): OAuth2AuthenticatedPrincipal {
        val authorized = delegate.introspect(token)
        return makeUserInfoRequest(authorized)
    }
}</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>Either way, having created your <a href="oauth2-resourceserver.html#oauth2resourceserver-opaque-architecture-introspector"><code>OpaqueTokenIntrospector</code></a>, you should publish it as a <code>@Bean</code> to override the defaults:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Bean
OpaqueTokenIntrospector introspector() {
    return new UserInfoOpaqueTokenIntrospector(...);
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">@Bean
fun introspector(): OpaqueTokenIntrospector {
    return UserInfoOpaqueTokenIntrospector(...)
}</code></pre>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="oauth2reourceserver-opaqueandjwt"><a class="anchor" href="oauth2-resourceserver.html#oauth2reourceserver-opaqueandjwt"></a>Supporting both JWT and Opaque Token</h2>
<div class="sectionbody">
<div class="paragraph">
<p>In some cases, you may have a need to access both kinds of tokens.
For example, you may support more than one tenant where one tenant issues JWTs and the other issues opaque tokens.</p>
</div>
<div class="paragraph">
<p>If this decision must be made at request-time, then you can use an <code>AuthenticationManagerResolver</code> to achieve it, like so:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Bean
AuthenticationManagerResolver&lt;HttpServletRequest&gt; tokenAuthenticationManagerResolver
        (JwtDecoder jwtDecoder, OpaqueTokenIntrospector opaqueTokenIntrospector) {
    AuthenticationManager jwt = new ProviderManager(new JwtAuthenticationProvider(jwtDecoder));
    AuthenticationManager opaqueToken = new ProviderManager(
            new OpaqueTokenAuthenticationProvider(opaqueTokenIntrospector));
    return (request) -&gt; useJwt(request) ? jwt : opaqueToken;
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">@Bean
fun tokenAuthenticationManagerResolver
        (jwtDecoder: JwtDecoder, opaqueTokenIntrospector: OpaqueTokenIntrospector):
        AuthenticationManagerResolver&lt;HttpServletRequest&gt; {
    val jwt = ProviderManager(JwtAuthenticationProvider(jwtDecoder))
    val opaqueToken = ProviderManager(OpaqueTokenAuthenticationProvider(opaqueTokenIntrospector));

    return AuthenticationManagerResolver { request -&gt;
        if (useJwt(request)) {
            jwt
        } else {
            opaqueToken
        }
    }
}</code></pre>
</div>
</div>
</div>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
The implementation of <code>useJwt(HttpServletRequest)</code> will likely depend on custom request material like the path.
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>And then specify this <code>AuthenticationManagerResolver</code> in the DSL:</p>
</div>
<div class="exampleblock">
<div class="title">Example 18. Authentication Manager Resolver</div>
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">http
    .authorizeRequests(authorize -&gt; authorize
        .anyRequest().authenticated()
    )
    .oauth2ResourceServer(oauth2 -&gt; oauth2
        .authenticationManagerResolver(this.tokenAuthenticationManagerResolver)
    );</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">http {
    authorizeRequests {
        authorize(anyRequest, authenticated)
    }
    oauth2ResourceServer {
        authenticationManagerResolver = tokenAuthenticationManagerResolver()
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Xml</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml">&lt;http&gt;
    &lt;oauth2-resource-server authentication-manager-resolver-ref="tokenAuthenticationManagerResolver"/&gt;
&lt;/http&gt;</code></pre>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="oauth2resourceserver-multitenancy"><a class="anchor" href="oauth2-resourceserver.html#oauth2resourceserver-multitenancy"></a>Multi-tenancy</h2>
<div class="sectionbody">
<div class="paragraph">
<p>A resource server is considered multi-tenant when there are multiple strategies for verifying a bearer token, keyed by some tenant identifier.</p>
</div>
<div class="paragraph">
<p>For example, your resource server may accept bearer tokens from two different authorization servers.
Or, your authorization server may represent a multiplicity of issuers.</p>
</div>
<div class="paragraph">
<p>In each case, there are two things that need to be done and trade-offs associated with how you choose to do them:</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>Resolve the tenant</p>
</li>
<li>
<p>Propagate the tenant</p>
</li>
</ol>
</div>
<div class="sect2">
<h3 id="_resolving_the_tenant_by_claim"><a class="anchor" href="oauth2-resourceserver.html#_resolving_the_tenant_by_claim"></a>Resolving the Tenant By Claim</h3>
<div class="paragraph">
<p>One way to differentiate tenants is by the issuer claim. Since the issuer claim accompanies signed JWTs, this can be done with the <code>JwtIssuerAuthenticationManagerResolver</code>, like so:</p>
</div>
<div class="exampleblock">
<div class="title">Example 19. Multitenancy Tenant by JWT Claim</div>
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">JwtIssuerAuthenticationManagerResolver authenticationManagerResolver = new JwtIssuerAuthenticationManagerResolver
    ("https://idp.example.org/issuerOne", "https://idp.example.org/issuerTwo");

http
    .authorizeRequests(authorize -&gt; authorize
        .anyRequest().authenticated()
    )
    .oauth2ResourceServer(oauth2 -&gt; oauth2
        .authenticationManagerResolver(authenticationManagerResolver)
    );</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">val customAuthenticationManagerResolver = JwtIssuerAuthenticationManagerResolver
    ("https://idp.example.org/issuerOne", "https://idp.example.org/issuerTwo")
http {
    authorizeRequests {
        authorize(anyRequest, authenticated)
    }
    oauth2ResourceServer {
        authenticationManagerResolver = customAuthenticationManagerResolver
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Xml</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml">&lt;http&gt;
    &lt;oauth2-resource-server authentication-manager-resolver-ref="authenticationManagerResolver"/&gt;
&lt;/http&gt;

&lt;bean id="authenticationManagerResolver"
        class="org.springframework.security.oauth2.server.resource.authentication.JwtIssuerAuthenticationManagerResolver"&gt;
    &lt;constructor-arg&gt;
        &lt;list&gt;
            &lt;value&gt;https://idp.example.org/issuerOne&lt;/value&gt;
            &lt;value&gt;https://idp.example.org/issuerTwo&lt;/value&gt;
        &lt;/list&gt;
    &lt;/constructor-arg&gt;
&lt;/bean&gt;</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>This is nice because the issuer endpoints are loaded lazily.
In fact, the corresponding <code>JwtAuthenticationProvider</code> is instantiated only when the first request with the corresponding issuer is sent.
This allows for an application startup that is independent from those authorization servers being up and available.</p>
</div>
<div class="sect3">
<h4 id="_dynamic_tenants"><a class="anchor" href="oauth2-resourceserver.html#_dynamic_tenants"></a>Dynamic Tenants</h4>
<div class="paragraph">
<p>Of course, you may not want to restart the application each time a new tenant is added.
In this case, you can configure the <code>JwtIssuerAuthenticationManagerResolver</code> with a repository of <code>AuthenticationManager</code> instances, which you can edit at runtime, like so:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">private void addManager(Map&lt;String, AuthenticationManager&gt; authenticationManagers, String issuer) {
	JwtAuthenticationProvider authenticationProvider = new JwtAuthenticationProvider
	        (JwtDecoders.fromIssuerLocation(issuer));
	authenticationManagers.put(issuer, authenticationProvider::authenticate);
}

// ...

JwtIssuerAuthenticationManagerResolver authenticationManagerResolver =
        new JwtIssuerAuthenticationManagerResolver(authenticationManagers::get);

http
    .authorizeRequests(authorize -&gt; authorize
        .anyRequest().authenticated()
    )
    .oauth2ResourceServer(oauth2 -&gt; oauth2
        .authenticationManagerResolver(authenticationManagerResolver)
    );</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">private fun addManager(authenticationManagers: MutableMap&lt;String, AuthenticationManager&gt;, issuer: String) {
    val authenticationProvider = JwtAuthenticationProvider(JwtDecoders.fromIssuerLocation(issuer))
    authenticationManagers[issuer] = AuthenticationManager {
        authentication: Authentication? -&gt; authenticationProvider.authenticate(authentication)
    }
}

// ...

val customAuthenticationManagerResolver: JwtIssuerAuthenticationManagerResolver =
    JwtIssuerAuthenticationManagerResolver(authenticationManagers::get)
http {
    authorizeRequests {
        authorize(anyRequest, authenticated)
    }
    oauth2ResourceServer {
        authenticationManagerResolver = customAuthenticationManagerResolver
    }
}</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>In this case, you construct <code>JwtIssuerAuthenticationManagerResolver</code> with a strategy for obtaining the <code>AuthenticationManager</code> given the issuer.
This approach allows us to add and remove elements from the repository (shown as a <code>Map</code> in the snippet) at runtime.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
It would be unsafe to simply take any issuer and construct an <code>AuthenticationManager</code> from it.
The issuer should be one that the code can verify from a trusted source like a list of allowed issuers.
</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="_parsing_the_claim_only_once"><a class="anchor" href="oauth2-resourceserver.html#_parsing_the_claim_only_once"></a>Parsing the Claim Only Once</h4>
<div class="paragraph">
<p>You may have observed that this strategy, while simple, comes with the trade-off that the JWT is parsed once by the <code>AuthenticationManagerResolver</code> and then again by the <a href="oauth2-resourceserver.html#oauth2resourceserver-jwt-architecture-jwtdecoder"><code>JwtDecoder</code></a> later on in the request.</p>
</div>
<div class="paragraph">
<p>This extra parsing can be alleviated by configuring the <a href="oauth2-resourceserver.html#oauth2resourceserver-jwt-architecture-jwtdecoder"><code>JwtDecoder</code></a> directly with a <code>JWTClaimsSetAwareJWSKeySelector</code> from Nimbus:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Component
public class TenantJWSKeySelector
    implements JWTClaimsSetAwareJWSKeySelector&lt;SecurityContext&gt; {

	private final TenantRepository tenants; <i class="conum" data-value="1"></i><b>(1)</b>
	private final Map&lt;String, JWSKeySelector&lt;SecurityContext&gt;&gt; selectors = new ConcurrentHashMap&lt;&gt;(); <i class="conum" data-value="2"></i><b>(2)</b>

	public TenantJWSKeySelector(TenantRepository tenants) {
		this.tenants = tenants;
	}

	@Override
	public List&lt;? extends Key&gt; selectKeys(JWSHeader jwsHeader, JWTClaimsSet jwtClaimsSet, SecurityContext securityContext)
			throws KeySourceException {
		return this.selectors.computeIfAbsent(toTenant(jwtClaimsSet), this::fromTenant)
				.selectJWSKeys(jwsHeader, securityContext);
	}

	private String toTenant(JWTClaimsSet claimSet) {
		return (String) claimSet.getClaim("iss");
	}

	private JWSKeySelector&lt;SecurityContext&gt; fromTenant(String tenant) {
		return Optional.ofNullable(this.tenantRepository.findById(tenant)) <i class="conum" data-value="3"></i><b>(3)</b>
		        .map(t -&gt; t.getAttrbute("jwks_uri"))
				.map(this::fromUri)
				.orElseThrow(() -&gt; new IllegalArgumentException("unknown tenant"));
	}

	private JWSKeySelector&lt;SecurityContext&gt; fromUri(String uri) {
		try {
			return JWSAlgorithmFamilyJWSKeySelector.fromJWKSetURL(new URL(uri)); <i class="conum" data-value="4"></i><b>(4)</b>
		} catch (Exception ex) {
			throw new IllegalArgumentException(ex);
		}
	}
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">@Component
class TenantJWSKeySelector(tenants: TenantRepository) : JWTClaimsSetAwareJWSKeySelector&lt;SecurityContext&gt; {
    private val tenants: TenantRepository <i class="conum" data-value="1"></i><b>(1)</b>
    private val selectors: MutableMap&lt;String, JWSKeySelector&lt;SecurityContext&gt;&gt; = ConcurrentHashMap() <i class="conum" data-value="2"></i><b>(2)</b>

    init {
        this.tenants = tenants
    }

    fun selectKeys(jwsHeader: JWSHeader?, jwtClaimsSet: JWTClaimsSet, securityContext: SecurityContext): List&lt;Key?&gt; {
        return selectors.computeIfAbsent(toTenant(jwtClaimsSet)) { tenant: String -&gt; fromTenant(tenant) }
                .selectJWSKeys(jwsHeader, securityContext)
    }

    private fun toTenant(claimSet: JWTClaimsSet): String {
        return claimSet.getClaim("iss") as String
    }

    private fun fromTenant(tenant: String): JWSKeySelector&lt;SecurityContext&gt; {
        return Optional.ofNullable(this.tenants.findById(tenant)) <i class="conum" data-value="3"></i><b>(3)</b>
                .map { t -&gt; t.getAttrbute("jwks_uri") }
                .map { uri: String -&gt; fromUri(uri) }
                .orElseThrow { IllegalArgumentException("unknown tenant") }
    }

    private fun fromUri(uri: String): JWSKeySelector&lt;SecurityContext?&gt; {
        return try {
            JWSAlgorithmFamilyJWSKeySelector.fromJWKSetURL(URL(uri)) <i class="conum" data-value="4"></i><b>(4)</b>
        } catch (ex: Exception) {
            throw IllegalArgumentException(ex)
        }
    }
}</code></pre>
</div>
</div>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>A hypothetical source for tenant information</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>A cache for `JWKKeySelector`s, keyed by tenant identifier</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>Looking up the tenant is more secure than simply calculating the JWK Set endpoint on the fly - the lookup acts as a list of allowed tenants</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>Create a <code>JWSKeySelector</code> via the types of keys that come back from the JWK Set endpoint - the lazy lookup here means that you don&#8217;t need to configure all tenants at startup</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>The above key selector is a composition of many key selectors.
It chooses which key selector to use based on the <code>iss</code> claim in the JWT.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
To use this approach, make sure that the authorization server is configured to include the claim set as part of the token&#8217;s signature.
Without this, you have no guarantee that the issuer hasn&#8217;t been altered by a bad actor.
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Next, we can construct a <code>JWTProcessor</code>:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Bean
JWTProcessor jwtProcessor(JWTClaimSetJWSKeySelector keySelector) {
	ConfigurableJWTProcessor&lt;SecurityContext&gt; jwtProcessor =
            new DefaultJWTProcessor();
	jwtProcessor.setJWTClaimSetJWSKeySelector(keySelector);
	return jwtProcessor;
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">@Bean
fun jwtProcessor(keySelector: JWTClaimsSetAwareJWSKeySelector&lt;SecurityContext&gt;): JWTProcessor&lt;SecurityContext&gt; {
    val jwtProcessor = DefaultJWTProcessor&lt;SecurityContext&gt;()
    jwtProcessor.jwtClaimsSetAwareJWSKeySelector = keySelector
    return jwtProcessor
}</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>As you are already seeing, the trade-off for moving tenant-awareness down to this level is more configuration.
We have just a bit more.</p>
</div>
<div class="paragraph">
<p>Next, we still want to make sure you are validating the issuer.
But, since the issuer may be different per JWT, then you&#8217;ll need a tenant-aware validator, too:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Component
public class TenantJwtIssuerValidator implements OAuth2TokenValidator&lt;Jwt&gt; {
	private final TenantRepository tenants;
	private final Map&lt;String, JwtIssuerValidator&gt; validators = new ConcurrentHashMap&lt;&gt;();

	public TenantJwtIssuerValidator(TenantRepository tenants) {
		this.tenants = tenants;
	}

	@Override
	public OAuth2TokenValidatorResult validate(Jwt token) {
		return this.validators.computeIfAbsent(toTenant(token), this::fromTenant)
				.validate(token);
	}

	private String toTenant(Jwt jwt) {
		return jwt.getIssuer();
	}

	private JwtIssuerValidator fromTenant(String tenant) {
		return Optional.ofNullable(this.tenants.findById(tenant))
		        .map(t -&gt; t.getAttribute("issuer"))
				.map(JwtIssuerValidator::new)
				.orElseThrow(() -&gt; new IllegalArgumentException("unknown tenant"));
	}
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">@Component
class TenantJwtIssuerValidator(tenants: TenantRepository) : OAuth2TokenValidator&lt;Jwt&gt; {
    private val tenants: TenantRepository
    private val validators: MutableMap&lt;String, JwtIssuerValidator&gt; = ConcurrentHashMap()
    override fun validate(token: Jwt): OAuth2TokenValidatorResult {
        return validators.computeIfAbsent(toTenant(token)) { tenant: String -&gt; fromTenant(tenant) }
                .validate(token)
    }

    private fun toTenant(jwt: Jwt): String {
        return jwt.issuer.toString()
    }

    private fun fromTenant(tenant: String): JwtIssuerValidator {
        return Optional.ofNullable(tenants.findById(tenant))
                .map({ t -&gt; t.getAttribute("issuer") })
                .map({ JwtIssuerValidator() })
                .orElseThrow({ IllegalArgumentException("unknown tenant") })
    }

    init {
        this.tenants = tenants
    }
}</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>Now that we have a tenant-aware processor and a tenant-aware validator, we can proceed with creating our <a href="oauth2-resourceserver.html#oauth2resourceserver-jwt-architecture-jwtdecoder"><code>JwtDecoder</code></a>:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Bean
JwtDecoder jwtDecoder(JWTProcessor jwtProcessor, OAuth2TokenValidator&lt;Jwt&gt; jwtValidator) {
	NimbusJwtDecoder decoder = new NimbusJwtDecoder(processor);
	OAuth2TokenValidator&lt;Jwt&gt; validator = new DelegatingOAuth2TokenValidator&lt;&gt;
			(JwtValidators.createDefault(), this.jwtValidator);
	decoder.setJwtValidator(validator);
	return decoder;
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">@Bean
fun jwtDecoder(jwtProcessor: JWTProcessor&lt;SecurityContext&gt;?, jwtValidator: OAuth2TokenValidator&lt;Jwt&gt;?): JwtDecoder {
    val decoder = NimbusJwtDecoder(jwtProcessor)
    val validator: OAuth2TokenValidator&lt;Jwt&gt; = DelegatingOAuth2TokenValidator(JwtValidators.createDefault(), jwtValidator)
    decoder.setJwtValidator(validator)
    return decoder
}</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>We&#8217;ve finished talking about resolving the tenant.</p>
</div>
<div class="paragraph">
<p>If you&#8217;ve chosen to resolve the tenant by something other than a JWT claim, then you&#8217;ll need to make sure you address your downstream resource servers in the same way.
For example, if you are resolving it by subdomain, you may need to address the downstream resource server using the same subdomain.</p>
</div>
<div class="paragraph">
<p>However, if you resolve it by a claim in the bearer token, read on to learn about <a href="oauth2-resourceserver.html#oauth2resourceserver-bearertoken-resolver">Spring Security&#8217;s support for bearer token propagation</a>.</p>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="oauth2resourceserver-bearertoken-resolver"><a class="anchor" href="oauth2-resourceserver.html#oauth2resourceserver-bearertoken-resolver"></a>Bearer Token Resolution</h2>
<div class="sectionbody">
<div class="paragraph">
<p>By default, Resource Server looks for a bearer token in the <code>Authorization</code> header.
This, however, can be customized in a handful of ways.</p>
</div>
<div class="sect2">
<h3 id="_reading_the_bearer_token_from_a_custom_header"><a class="anchor" href="oauth2-resourceserver.html#_reading_the_bearer_token_from_a_custom_header"></a>Reading the Bearer Token from a Custom Header</h3>
<div class="paragraph">
<p>For example, you may have a need to read the bearer token from a custom header.
To achieve this, you can expose a <code>DefaultBearerTokenResolver</code> as a bean, or wire an instance into the DSL, as you can see in the following example:</p>
</div>
<div class="exampleblock">
<div class="title">Example 20. Custom Bearer Token Header</div>
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Bean
BearerTokenResolver bearerTokenResolver() {
    DefaultBearerTokenResolver bearerTokenResolver = new DefaultBearerTokenResolver();
    bearerTokenResolver.setBearerTokenHeaderName(HttpHeaders.PROXY_AUTHORIZATION);
    return bearerTokenResolver;
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">@Bean
fun bearerTokenResolver(): BearerTokenResolver {
    val bearerTokenResolver = DefaultBearerTokenResolver()
    bearerTokenResolver.setBearerTokenHeaderName(HttpHeaders.PROXY_AUTHORIZATION)
    return bearerTokenResolver
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Xml</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml">&lt;http&gt;
    &lt;oauth2-resource-server bearer-token-resolver-ref="bearerTokenResolver"/&gt;
&lt;/http&gt;

&lt;bean id="bearerTokenResolver"
        class="org.springframework.security.oauth2.server.resource.web.DefaultBearerTokenResolver"&gt;
    &lt;property name="bearerTokenHeaderName" value="Proxy-Authorization"/&gt;
&lt;/bean&gt;</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>Or, in circumstances where a provider is using both a custom header and value, you can use <code>HeaderBearerTokenResolver</code> instead.</p>
</div>
</div>
<div class="sect2">
<h3 id="_reading_the_bearer_token_from_a_form_parameter"><a class="anchor" href="oauth2-resourceserver.html#_reading_the_bearer_token_from_a_form_parameter"></a>Reading the Bearer Token from a Form Parameter</h3>
<div class="paragraph">
<p>Or, you may wish to read the token from a form parameter, which you can do by configuring the <code>DefaultBearerTokenResolver</code>, as you can see below:</p>
</div>
<div class="exampleblock">
<div class="title">Example 21. Form Parameter Bearer Token</div>
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">DefaultBearerTokenResolver resolver = new DefaultBearerTokenResolver();
resolver.setAllowFormEncodedBodyParameter(true);
http
    .oauth2ResourceServer(oauth2 -&gt; oauth2
        .bearerTokenResolver(resolver)
    );</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">val resolver = DefaultBearerTokenResolver()
resolver.setAllowFormEncodedBodyParameter(true)
http {
    oauth2ResourceServer {
        bearerTokenResolver = resolver
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Xml</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml">&lt;http&gt;
    &lt;oauth2-resource-server bearer-token-resolver-ref="bearerTokenResolver"/&gt;
&lt;/http&gt;

&lt;bean id="bearerTokenResolver"
        class="org.springframework.security.oauth2.server.resource.web.HeaderBearerTokenResolver"&gt;
    &lt;property name="allowFormEncodedBodyParameter" value="true"/&gt;
&lt;/bean&gt;</code></pre>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_bearer_token_propagation"><a class="anchor" href="oauth2-resourceserver.html#_bearer_token_propagation"></a>Bearer Token Propagation</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Now that you&#8217;re resource server has validated the token, it might be handy to pass it to downstream services.
This is quite simple with <code><a href="https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/oauth2/server/resource/web/reactive/function/client/ServletBearerExchangeFilterFunction.html">ServletBearerExchangeFilterFunction</a></code>, which you can see in the following example:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Bean
public WebClient rest() {
    return WebClient.builder()
            .filter(new ServletBearerExchangeFilterFunction())
            .build();
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">@Bean
fun rest(): WebClient {
    return WebClient.builder()
            .filter(ServletBearerExchangeFilterFunction())
            .build()
}</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>When the above <code>WebClient</code> is used to perform requests, Spring Security will look up the current <code>Authentication</code> and extract any <code><a href="https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/oauth2/core/AbstractOAuth2Token.html">AbstractOAuth2Token</a></code> credential.
Then, it will propagate that token in the <code>Authorization</code> header.</p>
</div>
<div class="paragraph">
<p>For example:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">this.rest.get()
        .uri("https://other-service.example.com/endpoint")
        .retrieve()
        .bodyToMono(String.class)
        .block()</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">this.rest.get()
        .uri("https://other-service.example.com/endpoint")
        .retrieve()
        .bodyToMono&lt;String&gt;()
        .block()</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>Will invoke the <code><a href="https://other-service.example.com/endpoint" class="bare">https://other-service.example.com/endpoint</a></code>, adding the bearer token <code>Authorization</code> header for you.</p>
</div>
<div class="paragraph">
<p>In places where you need to override this behavior, it&#8217;s a simple matter of supplying the header yourself, like so:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">this.rest.get()
        .uri("https://other-service.example.com/endpoint")
        .headers(headers -&gt; headers.setBearerAuth(overridingToken))
        .retrieve()
        .bodyToMono(String.class)
        .block()</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">this.rest.get()
        .uri("https://other-service.example.com/endpoint")
        .headers{  headers -&gt; headers.setBearerAuth(overridingToken)}
        .retrieve()
        .bodyToMono&lt;String&gt;()
        .block()</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>In this case, the filter will fall back and simply forward the request onto the rest of the web filter chain.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
Unlike the <a href="https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/oauth2/client/web/reactive/function/client/ServletOAuth2AuthorizedClientExchangeFilterFunction.html">OAuth 2.0 Client filter function</a>, this filter function makes no attempt to renew the token, should it be expired.
To obtain this level of support, please use the OAuth 2.0 Client filter.
</td>
</tr>
</table>
</div>
<div class="sect2">
<h3 id="_resttemplate_support"><a class="anchor" href="oauth2-resourceserver.html#_resttemplate_support"></a><code>RestTemplate</code> support</h3>
<div class="paragraph">
<p>There is no <code>RestTemplate</code> equivalent for <code>ServletBearerExchangeFilterFunction</code> at the moment, but you can propagate the request&#8217;s bearer token quite simply with your own interceptor:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Bean
RestTemplate rest() {
	RestTemplate rest = new RestTemplate();
	rest.getInterceptors().add((request, body, execution) -&gt; {
		Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
		if (authentication == null) {
			return execution.execute(request, body);
		}

		if (!(authentication.getCredentials() instanceof AbstractOAuth2Token)) {
			return execution.execute(request, body);
		}

		AbstractOAuth2Token token = (AbstractOAuth2Token) authentication.getCredentials();
	    request.getHeaders().setBearerAuth(token.getTokenValue());
	    return execution.execute(request, body);
	});
	return rest;
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">@Bean
fun rest(): RestTemplate {
    val rest = RestTemplate()
    rest.interceptors.add(ClientHttpRequestInterceptor { request, body, execution -&gt;
        val authentication: Authentication? = SecurityContextHolder.getContext().authentication
        if (authentication != null) {
            execution.execute(request, body)
        }

        if (authentication!!.credentials !is AbstractOAuth2Token) {
            execution.execute(request, body)
        }

        val token: AbstractOAuth2Token = authentication.credentials as AbstractOAuth2Token
        request.headers.setBearerAuth(token.tokenValue)
        execution.execute(request, body)
    })
    return rest
}</code></pre>
</div>
</div>
</div>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
Unlike the <a href="https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/oauth2/client/OAuth2AuthorizedClientManager.html">OAuth 2.0 Authorized Client Manager</a>, this filter interceptor makes no attempt to renew the token, should it be expired.
To obtain this level of support, please create an interceptor using the <a href="oauth2-client.html#oauth2client" class="xref page">OAuth 2.0 Authorized Client Manager</a>.
</td>
</tr>
</table>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="oauth2resourceserver-bearertoken-failure"><a class="anchor" href="oauth2-resourceserver.html#oauth2resourceserver-bearertoken-failure"></a>Bearer Token Failure</h2>
<div class="sectionbody">
<div class="paragraph">
<p>A bearer token may be invalid for a number of reasons. For example, the token may no longer be active.</p>
</div>
<div class="paragraph">
<p>In these circumstances, Resource Server throws an <code>InvalidBearerTokenException</code>.
Like other exceptions, this results in an OAuth 2.0 Bearer Token error response:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-http request hljs" data-lang="http request">HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer error_code="invalid_token", error_description="Unsupported algorithm of none", error_uri="https://tools.ietf.org/html/rfc6750#section-3.1"</code></pre>
</div>
</div>
<div class="paragraph">
<p>Additionally, it is published as an <code>AuthenticationFailureBadCredentialsEvent</code>, which you can <a href="../authentication/events.html#servlet-events" class="xref page">listen for in your application</a> like so:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Component
public class FailureEvents {
	@EventListener
    public void onFailure(AuthenticationFailureBadCredentialsEvent badCredentials) {
		if (badCredentials.getAuthentication() instanceof BearerTokenAuthenticationToken) {
		    // ... handle
        }
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">@Component
class FailureEvents {
    @EventListener
    fun onFailure(badCredentials: AuthenticationFailureBadCredentialsEvent) {
        if (badCredentials.authentication is BearerTokenAuthenticationToken) {
            // ... handle
        }
    }
}</code></pre>
</div>
</div>
</div>
</div>
</div>
</div>
<nav class="pagination">
<span class="prev"><a href="oauth2-client.html">OAuth2 Client</a></span>
<span class="next"><a href="../saml2/index.html">SAML2</a></span>
</nav>
</article>
</div>
</main>
</div>
<footer class="footer flex">
<div id="spring-links flex">
<img id="springlogo" src="../../../_/img/spring-logo.svg" alt="Spring">
<p class="smallest antialiased">© <script>var d = new Date();
        document.write(d.getFullYear());</script> <a href="https://www.vmware.com/">VMware</a>, Inc. or its affiliates. <a href="https://www.vmware.com/help/legal.html">Terms of Use</a> • <a href="https://www.vmware.com/help/privacy.html" rel="noopener noreferrer">Privacy</a> • <a href="https://spring.io/trademarks">Trademark Guidelines</a> <span id="thank-you-mobile">• <a href="https://spring.io/thank-you">Thank you</a></span> • <a href="https://www.vmware.com/help/privacy/california-privacy-rights.html">Your California Privacy Rights</a> • <a class="ot-sdk-show-settings">Cookie Settings</a> <span id="teconsent"></span></p>
<p class="smallest antialiased">Apache®, Apache Tomcat®, Apache Kafka®, Apache Cassandra&trade;, and Apache Geode&trade; are trademarks or registered trademarks of the Apache Software Foundation in the United States and/or other countries. Java&trade;, Java&trade; SE, Java&trade; EE, and OpenJDK&trade; are trademarks of Oracle and/or its affiliates. Kubernetes® is a registered trademark of the Linux Foundation in the United States and other countries. Linux® is the registered trademark of Linus Torvalds in the United States and other countries. Windows® and Microsoft® Azure are registered trademarks of Microsoft Corporation. “AWS” and “Amazon Web Services” are trademarks or registered trademarks of Amazon.com Inc. or its affiliates. All other trademarks and copyrights are property of their respective owners and are only mentioned for informative purposes. Other names may be trademarks of their respective owners.</p>
</div>
<div id="social-icons" class="flex jc-between">
<a href="https://www.youtube.com/user/SpringSourceDev" title="Youtube"><svg id="youtube-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40"><circle class="cls-1" cx="20" cy="20" r="20" /><path class="cls-2" d="M30.91,14.53a2.89,2.89,0,0,0-2-2C27.12,12,20,12,20,12s-7.12,0-8.9.47a2.9,2.9,0,0,0-2,2A30.56,30.56,0,0,0,8.63,20a30.44,30.44,0,0,0,.46,5.47,2.89,2.89,0,0,0,2,2C12.9,28,20,28,20,28s7.12,0,8.9-.47a2.87,2.87,0,0,0,2-2A30.56,30.56,0,0,0,31.37,20,28.88,28.88,0,0,0,30.91,14.53ZM17.73,23.41V16.59L23.65,20Z" /></svg></a>
<a href="https://github.com/spring-projects" title="Github"><svg id="github-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 75.93 75.93"><path class="cls-1" d="M38,0a38,38,0,1,0,38,38A38,38,0,0,0,38,0Z" /></g><path class="cls-2" d="M38,15.59A22.95,22.95,0,0,0,30.71,60.3c1.15.21,1.57-.5,1.57-1.11s0-2,0-3.9c-6.38,1.39-7.73-3.07-7.73-3.07A6.09,6.09,0,0,0,22,48.86c-2.09-1.42.15-1.39.15-1.39a4.81,4.81,0,0,1,3.52,2.36c2,3.5,5.37,2.49,6.67,1.91a4.87,4.87,0,0,1,1.46-3.07c-5.09-.58-10.45-2.55-10.45-11.34a8.84,8.84,0,0,1,2.36-6.15,8.29,8.29,0,0,1,.23-6.07s1.92-.62,6.3,2.35a21.82,21.82,0,0,1,11.49,0c4.38-3,6.3-2.35,6.3-2.35a8.29,8.29,0,0,1,.23,6.07,8.84,8.84,0,0,1,2.36,6.15c0,8.81-5.37,10.75-10.48,11.32a5.46,5.46,0,0,1,1.56,4.25c0,3.07,0,5.54,0,6.29s.42,1.33,1.58,1.1A22.94,22.94,0,0,0,38,15.59Z" /></svg></a>
<a href="https://twitter.com/springcentral" title="Twitter"><svg id="twitter-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 75.93 75.93"><circle class="cls-1" cx="37.97" cy="37.97" r="37.97" /><path id="Twitter-2" data-name="Twitter" class="cls-2" d="M55.2,22.73a15.43,15.43,0,0,1-4.88,1.91,7.56,7.56,0,0,0-5.61-2.49A7.78,7.78,0,0,0,37,30a7.56,7.56,0,0,0,.2,1.79,21.63,21.63,0,0,1-15.84-8.23,8,8,0,0,0,2.37,10.52,7.66,7.66,0,0,1-3.48-1v.09A7.84,7.84,0,0,0,26.45,41a7.54,7.54,0,0,1-2,.28A7.64,7.64,0,0,1,23,41.09a7.71,7.71,0,0,0,7.18,5.47,15.21,15.21,0,0,1-9.55,3.37,15.78,15.78,0,0,1-1.83-.11,21.41,21.41,0,0,0,11.78,3.54c14.13,0,21.86-12,21.86-22.42,0-.34,0-.68,0-1a15.67,15.67,0,0,0,3.83-4.08,14.9,14.9,0,0,1-4.41,1.24A7.8,7.8,0,0,0,55.2,22.73Z" /></svg></a>
</div>
</footer>
<script src="../../../_/js/site.js"></script>
<script async src="../../../_/js/vendor/highlight.js"></script>
<script async src="../../../_/js/vendor/tabs.js"></script>
<script src="../../../_/js/vendor/switchtheme.js"></script>
<script src="../../../_/js/vendor/docsearch.min.js"></script>

<script>
var search = docsearch({
  appId: '244V8V9FGG',
  apiKey: '82c7ead946afbac3cf98c32446154691',
  indexName: 'security-docs',
  inputSelector: '#search-input',
  autocompleteOptions: { hint: false, keyboardShortcuts: ['s'] },
  algoliaOptions: { hitsPerPage: 10 }
}).autocomplete
search.on('autocomplete:closed', function () { search.autocomplete.setVal() })
</script>
<script>if (window.parent == window) {(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)})(window,document,'script','//www.google-analytics.com/analytics.js','ga');ga('create', 'UA-2728886-23', 'auto', {'siteSpeedSampleRate': 100});ga('send', 'pageview');}</script><script defer src="https://static.cloudflareinsights.com/beacon.min.js/v652eace1692a40cfa3763df669d7439c1639079717194" integrity="sha512-Gi7xpJR8tSkrpF7aordPZQlW2DLtzUlZcumS8dMQjwDHEnw9I7ZLyiOj/6tZStRBGtGgN6ceN6cMH8z7etPGlw==" data-cf-beacon='{"rayId":"702e405afa359830","token":"bffcb8a918ae4755926f76178bfbd26b","version":"2021.12.0","si":100}' crossorigin="anonymous"></script>
</body>
</html>
